Tech:Technotes 🔗


Содержание:

    HotLinkx
    Модификации кода
        Список всех вики-страниц
        Прикручиваем логотип в скин Modern
        MediaWiki:Common.css
        Иконка Youtube для ссылок на внешний Youtube-ресурс
        Модификация тега code
        Вставка документов
        Модификация модуля Videogallery - без субтитров
        Субтитры (YouTube)
        Субтитры (RuTube)
        3D-модели
        Генератор All Pages List
        Сокрытие блоков текста
    Практические моменты
        Transclusion
        Отключение нумерации в TOC
    Вопросы по системе
        Мультизагрузка картинок
            1. Скачивание картинок со страницы
            2. Модификация сервисного скрипта загрузки
            3. Загрузка картинок в Вику
        DJVU to PDF
        Bots
        Смена рутового пароля MySQL
        Virsh commands
    YurTube
    LUA-модули
        Videogallery
        Infobox
            synonyms()
            event_members()
            persons_activities()
    Subtitles
        Youtube API
        ytdl
    Настройка поискового движка
        Sphinx Search (deprecated)
        CyrrusSearch
        Модификация CyrrusSearch поиск по сорцам
    Public site
        Скин Erudit
        Скин Tweeki
            Иконки для ссылок
            Logo
            TOC
            Модификация модуля Videogallery
            Шаблон TODO
            Ссылки на эту страницу
            Панель subnav
            Custom Footer
            Hide file history table
            Поддержка другого субдомена (вики-ферма)
        Баг с subnav
        Блок категорий в футере
    Миграция вики
        Миграция страниц
        Миграция файлов
    Переезд на Veda.Wiki
        Подготовка нового сервера.
        Переезд Mediawiki
            Перенос файлов
            Перенос БД
    Настройка WikiFarm
        Install issues
        Upload Dir
        Общие таблицы для 2 вик
        Настройка интервики
        Оптимизация конфига Nginx
    Wiki Translation
    Настройка редактора
    Backup system
        Скрипты и файлы
        Установка
        Авторизация LDAP
            Предварительные мытарства и полезные фишки
                Configuration of LDAP extension hub
                Проблема с настройкой LDAP аутентификации
                Синхронизация групп
            LDAP сервер
            Смена пароля для LDAP админа (Manager)
            Dump and Restore
            phpldapadmin
            SSP
            Переключение скина при авторизации
    Баги и ошибки
        Баг на слове Трилитон
        DPL install issue
        DPL migration issue
    Tip'n'Tricks
        Отключение запрета на копирование в Telegram-группах
        Показ системных сообщений
        Страница логина
        Ссылки в футтере
        Подключение экстеншнов в цикле

Материал из VEDA Wiki
Перейти к: навигация, поиск

HotLinkx

Модификации кода

Список всех вики-страниц

Достигается небольшой DPL-конструкцией:

{{#dplvar:set |AllPages|
<DPL>
debug=1
category=
namespace=0
addcategories = true
redirects = include
mode=category
columns=3
titlematch=%%
replaceintitle=/(.*)(\d{10})\/(.*)/smi,UnknownPerson_$2
resultsfooter={{#dplvar:set |PagesCount|%PAGES%}}
</DPL>
}}

И затем в нужном месте страницы ставим переменную со сгенеренным списком:

В коде выше есть строка redirects = include. Она включает в список и все редиректы, ее можно выкинуть если не нужны редиректы. Но если оставить, редиректы будут цвета, похожего на обычные странички.

Предыдущие модификации перестали работать после переезда движка с версии 1.39 на 1.40 - устаревший DPL перестал работать с движком, в новом реализовано так:

<div style="column-count: 3;">
<DPL>
debug=1
category=
namespace=0
notnamespace = Campaign¦Шаблон¦Категория¦Модуль¦Tech¦File¦Субтитры¦MediaWiki¦Subtitles¦Template¦Category¦Module
ordermethod=titlewithoutnamespace
addcategories = true
includesubpages=false
redirects = include
mode=category
shownamespace=false
columns=3
titlematch=%%
replaceintitle=/(.*)(\d{10})\/(.*)/smi,UnknownPerson_$2
resultsfooter={{#dplvar:set |PagesCount|%PAGES%}}
</DPL>
</div>

В англ.версии убраны русские названия неймспейсов. В коде экстеншна (extensions/DynamicPageList3/includes/ParametersData.php:285) пришлось поправить параметр с 500 на 50000:

                       'default' => 50000,

Чтоб сменить цвет редиректных страниц надо в CSS-файл скина вставить код:

a.mw-redirect { color: #00AA00 !important;  }

Редиректы везде станут темнозелеными. К сожалению, стандартные рекомендации внесения в Common.css, Custom.css и даже Modern.css эффекта не возымели.

Note1 - движок очень инерционен и изменения отображаются не мгновенно!!
Note2 - фича раскраски шрифтов реализована только для текущего актуального скина Modern. В других цвета редиректов останутся дефолтными и там надо отдельно редактировать CSS-файл скина.

Прикручиваем логотип в скин Modern

Скин официально не работает с логотипом и не отображает его. Для прикручивания пришлось бы поломать всю разметку шаблонов страниц.. Но можно найти место на странице, где его можно вывести без последствий. К примеру вверху бокового меню. В файле skins/Modern/SkinModern.php ищем участок кода:

</div><!-- mw_contentwrapper -->

                        <div id="mw_portlets"<?php $this->html( "userlangattributes" ) ?>>
                                <h2><?php $this->msg( 'navigation-heading' ) ?></h2>

и вставляем после него:

<img src="/lahwiki_pyr01.png" width="100pt" align="top">

Есть еще способ с правкой modern.css но результат ужасен. Картинка становится бекграундом (проглядывающим только по краям стр.) с повторением, которое через CSS не отключалось.

MediaWiki:Common.css

На этой странице можно применить различные модификации стилей, для отображения на всех вики-страницах. Ранее упоминались модификации тега DIV..

Еще один интересный пример найден на https://wikihandbk.com/wiki/MediaWiki:Common.css - установка своих картинок на курсор мышки, разных - в зависимость от статуса курсора. Там же и много др. интересных примеров тюнинга.

Иконка Youtube для ссылок на внешний Youtube-ресурс

В MediaWiki:Common.css добавляем код CSS-селектора (more adv.expl.), ищущего ссылку начинающуюся на https://www.youtube или https://youtu.be:

/* https://en.wikipedia.org/wiki/MediaWiki:Common.css Change the external link icon to a Y icon for all Youtube URLs */
.mw-parser-output a[href^="https://www.youtube"].external,
.mw-parser-output a[href^="https://youtu.be"].external {
	/*background: url("images/f/f0/YouTube_full-24px.png") no-repeat right;*/
    background: url("images/8/81/YouTube_full-12px.png") no-repeat right;
	/* @noflip */
	padding: 8px 15px 8px 0;
}

В качестве параметра указана иконка загруженного файла (взят и конвертирован с commons.wikimedia.org)

Также по аналогии настроены иконки для сервисов RuTube, Telegram, VK, Facebook, Instagram, Wikipedia, Livejournal, Odnoklassniki, Yandex Dzen, Twitter, GoogleMaps.

Модификация тега code

Тег отображает текст моноширинным шрифтом. Изначально сделан для тог чтобы выделять им участки кода и команды. Но в данной вики для этого применяется экстеншн SyntaxHighlight. Поэтому решено использовать code для инлайн выделения всяких кнопочек, обозначений элементов интерфейса итп. Добавлен код в MediaWiki:Common.css:

/* Modification of code tag to set border */
code {
    padding: 2px 3px;
    font-family: monospace;
    background-color: #e0eeee;
    /* display: inline; */
    box-shadow: 1px 1px 3px #688;
}

Вставка документов

Штатный способ вставить на страницу файл (напр. PDF) в виде вики-ссылки, без отображения содержимого файла на странице:

<nowiki>
[[:Файл:FileName.ext|File Desrciption]]
</nowiki>

Предваряя имя файла двоеточием. Однако при данном способе на страничке файла не отображается список страниц, на которых этот файл был включен. Проблема не решаемы в силу особеностей устройства движка. Поэтому сделан шаблон для вставки файлов - Шаблон:File. Пользоваться так:

<nowiki>{{File| Файл:FileName.ext | File Desrciption }}</nowiki>

Шаблон реализован "по-колхозному", но зато максимально просто - на страничку инклудится код для вставки в виде ссылки (см.выше), а также и полная вставка всего содержимого, но вторая вставка скрыта средствами CSS. Также перед ссылкой подставляется иконка, в зависимости от типа файла. Также подставляется категория Страницы с документами.


Модификация модуля Videogallery - без субтитров

Если видео не содержит речи либо на видео отекстовка не была включена - ссылка на субтитры, очевидно, не нужна. В модуле Videogallery произведена модификация кода. Если в описании (после квадратных скобок с УРЛом видео и тайтлом) вписать тег <nosub> - вместо ссылки на субтитры будет светлосерая надпись (Без субтитров).

--format final code with iframe
function format_embed(d, u, t, c)
  e=get_embed(u)
+  if string.match(c,'<nosub>') then 
+     c = string.gsub(c,'(.-)(<nosub>)(.*)','%1%3')
+     ytid = '<br><span style="color: lightgray;">(Без субтитров)</span>'
+  end
  c=format_timestamp(u, c)
  return '<b>'..e..d..'<br>'..' ['..u..' '..t..']</b>'..ytid..'<br>'..c
end

Субтитры (YouTube)

Создан сервис по вытаскиванию субтитров из ютюб-видео и переформатирование в вики-разметку. Подразумевается, что странички с субтитрами располагаются в отдельном неймспейсе "Субтитры" с именами в виде их ИДшников.

Также добавлены настройки неймспейса в LocalSettings.php:

define("NS_SUBTITLES", 3000);
define("NS_SUBTITLES_TALK", 3001);
$wgExtraNamespaces[NS_SUBTITLES] = "Субтитры";
$wgExtraNamespaces[NS_SUBTITLES_TALK] = "Обсуждение_субтитров";
$wgContentNamespaces[]  =  3000;
$wgNamespacesToBeSearchedDefault[NS_SUBTITLES] = true;

После добавления нового неймспейса имевшиеся страницы не отображались в списке и были недоступны через поиск. Решилось командой:

  php mantainance/namespaceDupes.php --fix

Поиск не работал при ИД неймспейса 210, но заработал с 3000.

Доработан Модуль:Videogallery - для ютюб-роликов добавлена вставка ссылки на стр.субтитров. По цвету вики-ссылки видно, сгенерены ли для данного ролика субтитры.


Субтитры (RuTube)

RuTube собирается внедрять поддержку субтитров для видео, но пока все это в тестовом режиме, тестируется лишь на некоторых аккаунтах (в частности на Сане из Флориды). Как включить субтитры в Рутубе? Субтитры в Rutube - вкратце, пока никак.

API RuTube пока еще публично не документирован. Есть лишь небольшой FAQ по эмбеддингу видео. Из него следует, что доступ к опциям видео возможен по ссылке вида https://rutube.ru/api/play/options/{id_video} где id_video - идентификатор видяшки. На примере конкретного видео с субтитрами: https://rutube.ru/video/04932a0fcf016212d5054bb21026d04d/

https://rutube.ru/api/play/options/04932a0fcf016212d5054bb21026d04d - JSON-документ с различными параметрами. В нем обнаруживаются нужные ссылки: https://pic.rutube.ru/subtitle/73/0c/730ca12d7d162a348ed1123bb82747f9.srt - файл с субтитрами.

ИДшники в УРЛе генерятся на стороне сервера, по неизвестному алгоритму, так что придется вытаскивать финальный УРЛ из этого JSONа. Тут удобнее на все это смотреть. Вытащить субтитры можно таким простым скриптом на питоне:

import urllib.request, json

def getsrt(url):
    response = urllib.request.urlopen(url)
    data = json.loads(response.read())
##    print(data['captions'][0]['file'])
    return data

def main():
    url='https://rutube.ru/api/play/options/04932a0fcf016212d5054bb21026d04d' ## with subtitles
##    url = 'https://rutube.ru/api/play/options/4888cc47f15cdff3c15bb50ea52f8ccf/' ## without subtitles
    jsondata = getsrt(url)
    try:
##      print("", jsondata['captions'][0]['file'])
        f = urllib.request.urlopen(jsondata['captions'][0]['file'])
        myfile = f.read()
        print(myfile.decode("utf-8", "ignore"))
##      print(myfile)
    except:
        print("Subtitles are not available")

3D-модели

Обнаружилась возможность эмбедить на страничку 3D-модели с сайта https://sketchfab.com/ Заводить новый раздел в шаблонах смысла нет - модели имеются лишь по единичным объектам.. Поэтому пока вручную создаем после раздел 3D (ниже Фото) и там ставим теги <html>..</html> (эмбед в виде iframe). В случае нескольких эмбедов они не группируются в одну строку а располагаются один под др. (из-за встроенных div-ов). Чтоб заставить группироваться в строку, был модифицирован MediaWiki:Common.css - добавлен модификатор стиля, тянущегося с сайта:

.sketchfab-embed-wrapper {
  display: inline-block !important;
  border: 0px dotted;
  white-space: break-spaces;
  vertical-align: top;
  width: 350px;
}

Попытка добавить туда же

<pre>.sketchfab-embed-wrapper::before {content: "[[Категория:Страницы с 3D-моделями]]";}</pre>

не привела к желаемому результату - страница рендерится раньше включения эмбеда и тег с категорией вываливается текстом в страницу. Видимо надо написать обработчик наличия секции 3D Еще проще и универсальнее - указывать название раздела в фигурных скобках - вызывая соотв.шаблон (Шаблон:3D) в котором кроме текста названия секции вставляется также и категория. В шаблоне также организована секция подстановки для плагина TplInsert, и добавлен пункт в инструментах редактора.

Генератор All Pages List

Изначально был написан с использованием DPL, но в процессе обновления версий вики сначала прежние DPL-экстеншны оказывались deprecated, потом актуальные начали нестабильно себя вести. Поэтому было намечено сделать собственное решение. В качестве основы взят экстеншн Extension:Newest_Pages и немного переделан.

Модификации в extensions/NewestPages/SpecialNewestPages.php:

71c71
<                               'ORDER BY' => 'page_id DESC',
---
>                               'ORDER BY' => 'page_title ASC',
98,100c98,107
<                       $out->addHTML( '<ol>' );
<                       foreach ( $res as $row ) {
<                               $out->addHTML( $this->makeListItem( $row ) );
---
>
>               $out->addHTML( $this->genTOC( $res ) );
>               $out->addHTML( $count . $out->msg( 'newestpages-count' )->text() . '<br>'.'<div style="column-count: 3;"><ul>' );
>
>               $current_title_char = '';
>               foreach ( $res as $row ) {
>                       $title_char = mb_substr(Title::newFromRow( $row ), 0, 1);
>                       if ($title_char !== $current_title_char){
>                               $out->addHTML( '<a name="' . $title_char . '"><h3>' . $title_char . '</h2></a>' );
>                               $current_title_char = $title_char;
102c109,111
<                       $out->addHTML( '</ol>' );
---
>                       $out->addHTML( $this->makeListItem( $row ) );
>               }
>               $out->addHTML( '</ul></div>' );
129c138
<               return min( (int)$limit, 5000 );
---
>               return min( (int)$limit, 50000 );
184a194,211
>
>
>       /*
>       * Generate TOC from first symbols of all pages
>       */
>       private function genTOC( $res ) {
>               $toc = array();
>               foreach ($res as $row) {
>                       $title = mb_substr(Title::newFromRow( $row ), 0, 1);
>                       $title = '<a href="#'.$title.'">' . $title . '</a> ';
>                       $toc[$title] = '';
>               }
>
>               return '<div class="toccolours mw-collapsible mw-collapsed" data-expandtext="+" data-collapsetext="-" style="width:100%; display: table-cell; margin: 0.5em 0 0 2em">
> <h3>' . $this->msg( 'newestpages-toc' )->plain() . '</h3>
> <div class="mw-collapsible-content" style="text-align: center">'.implode(array_keys($toc)).'</div></div><br>';
>       }
>

Тут в с.4 - сортировка списка страниц по алфавиту. С.11 - вызов новой фции, генерирующей TOC из первых символов имеющихся страниц (динамическое решение, лучше чем прежний статичный список, поддерживает и нелатинские/некириллические символы). С12 - замена нумерованного списка на ненумерованный, форматирование списка в 3 колонки. С.16-19 - реализация оформления по типу страниц категорий - 1й символ делается заголовком и под ним выводится список страниц на этот символ.. С.29 - лимит на количество страниц повышен на 50000, иначе вывод неполный. С.36-47 - код добавленной фции генератора TOC.

Также добавлена локализация. В extensions/NewestPages/i18n/en.json:

        "newestpages-count": " pages",
        "newestpages-toc": "Alphanumeric TOC:",

В extensions/NewestPages/i18n/ru.json:

        "newestpages-count": " страниц",
        "newestpages-toc": "Буквенно-цифровой указатель:",

В LocalSettings.php:

wfLoadExtension( 'NewestPages' );
$wgNewestPagesLimit = 50000;

Код заглавной страницы теперь такой:

[[en:Main_Page]]
{{GoTop}}
{{Special:Newestpages/-}}

TODO: Возможно лучшим будет написать полностью свое расширение, избавившись от лишнего функционала исходного экстеншна.


Сокрытие блоков текста

Возникла необходимость сокрытия конфиденциальных данных на страницах людей при публичном просмотре (от имени неавторизованного пользователя). Решение с помощью CSS (организованное в скине Tweeki) привязано к скину и к тому же производит только внешнее сокрытие - в HTML-коде все данные остаются видны и будут индексированы поисковиками. Поэтому сделан отдельный экстеншн HideBlock вводящий новые теги <hide> .. </hide>. Текст внутри тегов блокируется на стадии сервера, перед рендерингом. Применен в шаблоне Персона к строкам генерируемой таблицы с данными о дате рождения-смерти, а также адреса, телефона, URL, e-mail.. Т.к. отрабатывает до рендеринга, то не происходит и генерации категорий из блокируемых параметров (категории возраста, даты рожд., соцсетей..). Пока без параметров, проверяет только ID юзера - если не 0 (анонимный), то выводит охваченный текст все как есть с полноценным рендерингом, иначе - возвращает пустую строку. Также применен и к шаблону TODO. Модификации шаблонов сделаны для обеих вик.

Код HideBlock/Hooks.php:
<?php

class HideBlockHooks {

    public static function wfHideBlockSetup( Parser $parser ) {
        $parser->setHook( 'hide', 'HideBlockHooks::wfHideBlock' );
    }

    public static function wfHideBlock( $input, array $args, Parser $parser, PPFrame $frame ) {
    $current_user = $parser->getUserIdentity()->mId;
        if ( $current_user >0 ){
            return $parser->recursiveTagParse( $input, $frame );
        }
        else {
            return "";
        }
    }
}

Тут в с.12 вывод с рендером. Если выводить просто $input - будет выводить сырой текст со всей разметкой, шаблоны поломаются.. С.10 - $parser->getUserIdentity() выдает много полезной инфы о текущем юзере. Но без принадлежности к группам..

Код HideBlock/extension.json:
{
        "name": "HideBlock",
        "author": [
                "Sphynkx"
        ],
        "url": "http://localhost",
        "descriptionmsg": "hideblock-desc",
        "license-name": "GPL-2.0-or-later",
        "type": "other",
        "requires": {
                "MediaWiki": ">= 1.35.0"
        },
    "MessagesDirs": {
        "HideBlock": [
            "i18n"
        ]
    },
    "AutoloadClasses": {
        "HideBlockHooks": "Hooks.php"
    },
    "Hooks": {
        "ParserFirstCallInit": "HideBlockHooks::wfHideBlockSetup"
    },  "manifest_version": 1
}
Код HideBlock/i18n/en.json:
{
        "@metadata": {
                "authors": [
                        "Sphynkx"
                ]
        },
        "hideblock-desc": "This is an HideBlock extension"
}
Код HideBlock/i18n/qqq.json:
{
        "@metadata": {
                "authors": [
                        "Sphynkx"
                ]
        },
        "hideblock-desc": "{{desc|name=HideBlock|url=http://localhost}}"
}
TODO: Для вставки тегов можно прикрутить кнопочку в панели инструментов редактора..
PS: Подсмотрено в ConsoleOutput и I18nTags.

Практические моменты

Transclusion

Вставка части страницы в другую страницу. В коде исходной страницы охватываем нужную часть в теги:

 <onlyinclude>...‎</onlyinclude>

Затем коде другой страницы, в необходимом месте указываем имя первой страницы в фигурных скобках и с двоеточием вначале:

 {{:A}}

Отключение нумерации в TOC

В MediaWiki:Common.css добавляем:

.tocnumber {display: none;}

Вопросы по системе

Мультизагрузка картинок

Т.к. наиболее удобный мультизагрузчик ныне поломан, приходится делать мультизагрузку такими более сложными способами.. Все действия происходят на сервере в консоли.

1. Скачивание картинок со страницы

Создаем отдельный каталог и в нем запускаем:

for i in `lynx -dump -listonly -nonumbers URL_СТРАНИЦЫ | grep jpg`; do wget $i ; done

2. Модификация сервисного скрипта загрузки

Штатный скрипт /var/www/wiki/maintenance/importImages.php чуть модифицирован (перед выводящимися именами для удобства последующей вставки добавляем "File:"):

diff importImages.php importImagesFormated.php
249c249,250
< 					$this->output( "Importing {$base}..." );
---
> ##					$this->output( "Importing {$base}..." );
> 			echo( "File:{$base}" );
339c340,341
< 					$this->output( "done.\n" );
---
> ##					$this->output( "done.\n" );
> 			echo( "\n" );

3. Загрузка картинок в Вику

Переходим в каталог со скачанными ранее картинками, и там запускаем скрипт следующего содержания:

#!/bin/bash
k=1000; for i in `ls -t` ; do k=$((k+1)); mv ./$i $k-$i ; done
sleep 3
php /var/www/wiki/maintenance/importImagesFormated.php $@ --conf=/var/www/wiki/LocalSettings_lahwiki.php --user=Sphynkx $(pwd) | sort | tee lahupload.log
chown -R apache:apache /var/www/wiki/images

Кроме загрузки картинок также распечатывается список загруженных файлов уже в Вики-формате, который копипастим на целевую Вики-страничку.

DJVU to PDF

Via commandline in Linux:

ddjvu -format=pdf filename.djvu filename.pdf

Bots

All Bots

https://github.com/greencardamom/Wikiget - awk script: auth, edit, search and replace, etc. 91.2 KB https://github.com/greencardamom/Wikiget/raw/master/wikiget.awk

https://github.com/BorderCloud/bash-mediawiki https://github.com/BorderCloud/bash-mediawiki/blob/main/testEditUploadWithBot.sh 4.91 KB

Смена рутового пароля MySQL

В соответствии с рекомендациями:

service mysql stop
mysqld_safe --skip-grant-tables &
service mysql start
mysql -u root
use mysql;
show tables;
describe user;
update user set authentication_string=password('Vebhf8rf') where user='root';
FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED BY 'Vebhf8rf';
FLUSH PRIVILEGES;

В принципе команды от use mysql до ALTER USER.. не нужны. Главное - запуститься без grant-tables. Команда update user.. выдала ERROR 1348 (HY000): Column 'authentication_string' is not updatable


Virsh commands

Список ВМок:

  virsh list

Список снапшотов ВМки:

   virsh snapshot-list --domain lah

Создание нового снапшота:

  virsh snapshot-create-as --domain lah --name "lah_snapshot2" --description "after lah_snapshot1"

Откат на предыдущий снапшот:

  virsh snapshot-revert --domain lah --snapshotname lah_snapshot1 --running

Когда не запускается виртуалка из-за мнимой нехватки памяти (ошибка: внутренняя ошибка: qemu unexpectedly closed the monitor: Cannot set up guest memory 'pc.ram': Cannot allocate memory) - даем команду:

  echo 1 > /proc/sys/vm/overcommit_memory

Но наверное так лучше не делать - замечено внезапное падение другой виртуалки (вероятно, не поделили память).

YurTube

Установка и настройка собственного видеохостинга по типу Ютюба..

В связи с разрастанием раздела новой инфой по новой версии движка, раздел перенесен в отдельную вику. Инфа раздела (отчасти устаревшая) сохранена там же отдельно.

LUA-модули

Для реализации сложной логики, вычислений, упрощения кода и облегчения расширяемости некоторые вещи были реализованы в виде LUA-модулей и расширения Scribunto.

Videogallery

Модуль:Videogallery предназначен для представления форматированного списка видеороликов в видеогалерею. Модуль поддерживает пока лишь YouTube, RuTube и YurTube.

Infobox

Модуль:Infobox содержит различные функции (пока 1) обработки параметров инфобокса.

synonyms()

Фция synonyms() принимает список, разделенный точкой с запятой и преобразует его в в группу ссылок на страницы (которые надо создать вручную и сделать перенаправление). Опциональный параметр itemlist=true используется в фантомных шаблонах для того чтобы при выводе убирать скобки и не использовать точку с запятой в качестве разделителя.

event_members()

Фция event_members() принимает данные из параметра Участники и форматирует вывод в виде элементов таблицы. Данные состоят из групповых параметров, разделяющихся  ! (с пробелами вокруг), каждая группа на отдельной строке и заканчивается ;. Также вычисляется общее количество участников - из расчета по одному на каждую группу. Если в групповых параметрах задано Количество - то к счетчику прибавляется это значение.

persons_activities()

Фция persons_activities() принимает неименованный список и несколько именованных параметров. Список - групповой параметр по аналогии с таковым в #event_members(). Именованные параметры (activity_title, activity_area, activity_position) задают названия полей в инфобоксе.

Subtitles

См. также #Субтитры (YouTube).
Создан сервис для генерации субтитров в формате вики-разметки, для последующей вставки в страницу. Код проекта: https://github.com/sphynkx/subtitles

Сервис принимает URL Youtube-ролика. Также есть "секретный" параметр ?from подключающий переводчик субтитров на русский. Этот параметр также выведен на точку в заголовке на страничке сервиса..

Изначально код был основан на стороннем сервисе вытягивания субтитров из Youtube-роликов. Однако потом этот сервис был заблокирован Ютюбом. Надо переделать на что-то более надежное.

Есть проблема - забыт формат, в котором принимались данные от стороннего сервиса, а посмотреть негде..


Youtube API

Youtube позволяет скачивать субтитры. Согласно рекомендациям надо выкачать страницу по УРЛу видео и найти в ней слово timedtext. Оно будет частью временного УРЛа с субтитрами. В этом УРЛе меняем \u0026 на &. Получается выхлоп в виде

<?xml version="1.0" encoding="utf-8" ?><transcript><text start="24.75" dur="4.599">строка с субтитром</text> .. </transcript>

..и это очень похоже на то, что выдавал сторонний сервис.. Надо попробовать. Сделано.

ytdl

Локальная утилита позволяющая широкий спектр манипуляций с youtube-video (см. https://github.com/ytdl-org/youtube-dl). Команда:

yt-dlp --write-auto-sub --sub-format ttml --convert-subs vtt --sub-lang ru --skip-download https://www.youtube.com/watch?v=cdEmz7HD29YcdEmz7HD29Y

выдает корректный vtt-файл с субтитрами, быстро - без предварительного скачивания видео.

Настройка поискового движка

Sphinx Search (deprecated)

Extension перестал обновляться с версии 1.33 и в 1.39 оказался совсем поломан.. Проба перехода на CyrrusSearch

Ставим поисковый движок в систему

dnf install sphinx

и пишем конфиг (креды из конфига МедиаВики):

#
# Minimal Sphinx configuration sample (clean, simple, functional)
#

source src_lahwiki_main
{
    type                        = mysql

    sql_host            = localhost
    sql_user            = <db_username>
    sql_pass            = <db_password>
    sql_db              = lah_wiki
    sql_port            = 3306  # optional, default is 3306

sql_query_pre = SET CHARACTER_SET_RESULTS=utf8
sql_query_pre = SET NAMES utf8

    sql_query           = SELECT page_id, page_title, page_namespace, page_is_redirect, old_id, old_text FROM page, revision, text WHERE rev_id=page_latest AND old_id=rev_text_id

# attribute columns
    sql_attr_uint       = page_namespace
    sql_attr_uint       = page_is_redirect
    sql_attr_uint       = old_id
 
# collect all category ids for category filtering
    sql_attr_multi  = uint category from query; SELECT cl_from, page_id AS category FROM categorylinks, page WHERE page_title=cl_to AND page_namespace=14 
# used by command-line search utility to display document information
##    sql_query_info    = SELECT page_title, page_namespace FROM page WHERE page_id=$id

}

# data source definition for the incremental index
source src_lahwiki_incremental : src_lahwiki_main
{
    # adjust this query based on the time you run the full index
    # in this case, full index runs at 7 AM UTC
    sql_query   = SELECT page_id, page_title, page_namespace, page_is_redirect, old_id, old_text FROM page, revision, text WHERE rev_id=page_latest AND old_id=rev_text_id AND page_touched>=DATE_FORMAT(CURDATE(), '%Y%m%d070000') 
    # all other parameters are copied from the parent source
}

index lahwiki_main
{
    source                      = src_lahwiki_main
    path                        = /var/lib/sphinx/lahwiki_main
    docinfo                     = extern

    # minimum word length
    min_word_len        = 1
 
    # allow wildcard (*) searches
    min_infix_len = 1
##    enable_star = 1

    # charset encoding type
##    charset_type      = utf-8 ## didnt search russian..
##    charset_type      = sbcs ## searched russian

charset_table = 0..9, A..Z->a..z, _, a..z, \
    U+410..U+42F->U+430..U+44F, U+430..U+44F, U+401->U+451, U+451

morphology = stem_enru

}

# incremental index definition
index lahwiki_incremental : lahwiki_main
{
    path                = /var/lib/sphinx/data/lahwiki_incremental
    source              = src_lahwiki_incremental
}
 
 
# indexer settings
indexer
{
    # memory limit (default is 32M)
    mem_limit   = 64M
}

# searchd settings
searchd
{
    # IP address and port on which search daemon will bind and accept
    listen              = 127.0.0.1:9312
 
    # searchd run info is logged here - create or change the folder
    log         = /var/log/sphinx/searchd.log
 
    # all the search queries are logged here
    query_log   = /var/log/sphinx/query.log
 
    # client read timeout, seconds
    read_timeout        = 5
 
    # maximum amount of children to fork
    max_children        = 30
 
    # a file which will contain searchd process ID
    pid_file    = /var/run/sphinx/searchd.pid
 
    # maximum amount of matches this daemon would ever retrieve
    # from each index and serve to client
#    max_matches = 1000
 
        # Remove warning of deprecated function        compat_sphinxql_magics = 0
}

Создаем папку /var/data (об этом почему то в мануалах не упоминается) Инициализируем индексацию и запускаем:

 /usr/bin/searchd --install  --config /etc/sphinx/sphinx.conf 
 /usr/bin/searchd  --config /etc/sphinx/sphinx.conf 
 /usr/bin/indexer  --config /etc/sphinx/sphinx.conf --all

Далее обновление индексов будет командой

 /usr/bin/indexer  --config /etc/sphinx/sphinx.conf --all --rotate

Скачиваем и ставим экстеншн в медиавику

  wget https://web.archive.org/web/20190423013516/https://extdist.wmflabs.org/dist/extensions/SphinxSearch-REL1_29-df738c5.tar.gz

Из еще более старой версии подкидываем в папку экстеншна файлик sphinxapi.php В конфиге медиавики пишем:

## Powerfull search engine with morphology. Replace for MW-std search
$wgSearchType = 'SphinxMWSearch';
require_once "$IP/extensions/SphinxSearch/SphinxSearch.php";
$wgSphinxSearch_index = "lahwiki_main";
$wgSphinxSearchMWHighlighter = true;
$wgFooterIcons['poweredby']['sphinxsearch'] = array(
        'src' => "$wgScriptPath/extensions/SphinxSearch/imgs/sphinx_silver.gif",
       'url' => 'http://www.mediawiki.org/wiki/Extension:SphinxSearch',
       'alt' => 'Search Powered by Sphinx',
       );

Проверяем все ли хорошо. Если да - ставим в крон:

  */5 * * * * /usr/bin/indexer --quiet --config /etc/sphinx/sphinx.conf lahwiki_main --rotate >/dev/null 2>&1; /usr/bin/indexer --quiet --config /etc/sphinx/sphinx.conf lahwiki_incremental --rotate >/dev/null 2>&1
ИНФА

картинка для кнопки отсюда

CyrrusSearch

Ставится штатно по мануалам с сайта (они могут меняться в зависимости от версии). Ошибок нет, но похоже что не проиндексированы все страницы. Некоторые слова (Кабрера, Ика, латинская "A") в поиске выводят единственную страницу (Кабрера). Иные (даже употребительные) не находятся.

curl -X GET "http://127.0.0.1:9200/_search?q=Ica&pretty"

В консоли кириллицу не понимает - только в виде urlencode.

Помогла (??) повторная переиндексация

  Step 0. -> in LocalSettings.php: $wgDisableSearchUpdate = true
  Step 1. -> php extensions/CirrusSearch/maintenance/UpdateSearchIndexConfig.php
  Step 2. -> in LocalSettings.php: #$wgDisableSearchUpdate = true
  Step 3. -> php extensions/CirrusSearch/maintenance/ForceSearchIndex.php --skipLinks --indexOnSkip
  Step 4. -> php extensions/CirrusSearch/maintenance/ForceSearchIndex.php --skipParse
  Step 5. -> php maintenance/runJobs.php

Before:

  curl localhost:9200/lah_wiki/_count?pretty
    {
    "count" : 41,
    "_shards" : {
      "total" : 2,
      "successful" : 2,
      "skipped" : 0,
      "failed" : 0
    }
  }

After:

  curl localhost:9200/lah_wiki/_count?pretty
  {
    "count" : 3071,
    "_shards" : {
      "total" : 2,
      "successful" : 2,
      "skipped" : 0,
      "failed" : 0
    }
  }

Поиск производится только по видимому содержимому (можно ли сделать дефолтом??). Для поиска по сорцам перед искомым словом надо добавлять insource:

После создания доп.вики в вики-ферме обнаружилось, что во 2й вике поиск не заработал. После переключения LocalSettings.php в режим 2й вики (заменой имени БД и врем. закомментриванием блока switch) команда php extensions/CirrusSearch/maintenance/UpdateSearchIndexConfig.php выдала:

        Inferring index identifier...error
Looks like the index has more than one identifier. You should delete all
but the one of them currently active. Here is the list: lah_wiki_en_content,lah_wiki_en_content_first

а команда curl -X GET "localhost:9200/_cat/indices" :

green  open .geoip_databases          p_j9rFvhTkKEFalitgfZsQ 1 0   38   0  36.7mb  36.7mb
green  open lah_wiki_content_first    mRhMe84tQ1utYkDyX_MHVQ 1 0  526  83  86.1mb  86.1mb
green  open mw_cirrus_metastore_first LEep8inzTCu5P2JOEQJw0g 1 0   47 102  54.8kb  54.8kb
green  open lah_wiki_en_content_first g0Zz5dj3SKamadnBfzPw7Q 1 0    0   0    227b    227b
green  open lah_wiki_general_first    ggzKtKnVT6CXeX2M853WuQ 1 0 4721 219   291mb   291mb
yellow open my-index-000002           o1SGqF7TQ1uS6m6QLN6ThA 1 1    0   0    227b    227b
yellow open my-index-000001           7tUM_T12SPC2JMLESrziSQ 1 1    0   0    227b    227b
yellow open lah_wiki_en_content       lfp8Hk15Q-aFIVWToQ5mzw 1 1    2  17    40kb    40kb
yellow open lah_wiki_en_general       tyeL78KFRVabenAcgAMH1w 1 1   63  60 658.2kb 658.2kb

После удаления:

curl -X DELETE "localhost:9200/lah_wiki_en_general"
curl -X DELETE "localhost:9200/lah_wiki_en_content"
curl -X DELETE "localhost:9200/lah_wiki_en_content_first"
curl -X DELETE "localhost:9200/my-index-000002"

и переинициализации поиска - все заработало..

Модификация CyrrusSearch поиск по сорцам

Как указывалось выше, по умолчанию поиск производится только по видимому содержимому - элементы разметки, участки URL итп в результаты не попадают. Для полноценного поиска нужно указывать префикс insource:. Штатных возможностей включения этого режима по умолчанию не обнаружилось, пришлось поправить в коде (extensions/CirrusSearch/includes/Searcher.php):

--- Searcher.php_ISX    2023-08-05 19:15:24.543949275 +0300
+++ Searcher.php        2023-08-05 19:23:41.817949275 +0300
@@ -294,11 +294,14 @@
                // whitespace. Cirrussearch treats them both as normal whitespace, but
                // the preceding isn't appropriately trimmed.
                // No searching for nothing! That takes forever!
+               global $wgInSourceSearchDefault;
                $term = trim( str_replace( "\xE3\x80\x80", " ", $term ) );
                if ( $term === '' ) {
                        $this->searchContext->setResultsPossible( false );
                }
-
+               if ( isset( $wgInSourceSearchDefault ) && $wgInSourceSearchDefault === true ) {
+                       $term = "insource:" . $term;
+               }
                $builderSettings = $this->config->getProfileService()
                        ->loadProfileByName( SearchProfileService::FT_QUERY_BUILDER,
                                $this->searchContext->getFulltextQueryBuilderProfile() );

Также в LocalSettings.php возле подключения экстеншна добавляем параметр

  $wgInSourceSearchDefault = true;

Для возврата в исходное поведение ставим его в false или закоментариваем.

TODO: Было бы неплохо вывести в виде галки на странице поиска.

Public site

Вика сейчас работает в 2 режимах - редакторском и публичном. Редакторский - это режим для создания и редактирования статей, загрузки файлов итд. С адм.привилегиями - еще и для настроек. Имеет доступ ко всем сайдбарам/линкам - штатным и донастроенным. Редакторский режим использует скин Modern - он аскетичен и прост, однако внедрение новых элементов оформления с ним проблематичны.

Публичный режим предназначен для показа контента вики без возможности управления и редактирования. Публичный режим предполагается настроить как режим для неавторизованных юзеров. В нем будут отключены сайдбары, линки на вики-инструменты (редактирование, история, обсуждение..) а также логин в систему. Для публичного режима будет предусмотрен отдельный скин, который имеет возможности гибкой настройки и расширения. В данный момент наружу торчит лишь Main_Page.

Временно, для разработки и настройки, неавторизованный режим имитирован от имени спец.юзера - SkinTest. Юзеру в настройках выставлен некий определенный скин (который сейчас подыскивается и будет настраиваться). Затем юзер блокируется, чтобы не имел возможности редактирования.

Теоретически, в настройках можно отключить редактирование всей группе (SkinTest внесен в группу probe):

$wgGroupPermissions[ 'probe' ][ '*' ] = false;
$wgGroupPermissions[ 'probe' ][ 'edit' ] = false;
$wgGroupPermissions[ 'probe' ][ 'createpage' ]  =  false ;

однако это не работает..

В пуб.версии некоторые страницы не должны быть доступны и отображаться в общем списке страниц. Для этого сделан новый неймспейс Tech и в него перенесены некоторые страницы. Есть возможность скрывать на пуб.версии страницы некоторые элементы. Сделано это путем определения класса tech MediaWiki:Tweeki.css. Затем в элементе HTML-разметки указываем class="tech". Напр.:

<span class="tech">Скрытый текст или элемент</span>

Подробности в #Скин Tweeki. Можно даже задуматься о разработке доп.тега <hide>..</hide>и кнопке в панели редактора..


Далее, некоторые опробованные скины..

Скин Erudit

Skin:Erudite

Простой и красивый скин, сделан по мотивам тем WordPress. Однако почти не имеет настроек, если что-то добавлять - придется дописывать код.

Внесенные в код изменения (Erudite.skin.php):

56c56,62
<
---
> <style>
> .lah-hide,
> .mw-editsection
>     {
>     display: none;
>     }
> </style>
94c100
<                       <div id="nav-meta">
---
>                       <div id="nav-meta" class="lah-hide">
113c119
<                       <div id="footer">
---
>                       <div id="footer" style="display:none;">
135c141,153
<                       <?php $this->html( 'catlinks' ); ?>
---
> <?php
> $title = $this->data['skin']->getTitle();
> $categories = $title->getParentCategories();
> ##print_r($categories);
> echo '<div id="catlinks" class="mw-normal-catlinks" data-mw="interface"><a href="/Special:Categories"">Categories:</a><br>';
> foreach ( $categories as $cat => $_) {
>     echo"<a href='$cat'>", preg_replace("/.*?\:/","", $cat),"</a>; ";
>     }
> echo "</div>";
> ?>
>                       <?php $this->html( 'catlinks_DIZABLED' ); ?><!-- Displays categories list in bottom -->
>
>
138c156
<               <div id="bottom-wrap">
---
>               <div id="bottom-wrap" class="lah-hide">

Тут в с.4-10 добавлен стиль для нового класса lah-hide - им отключаются элементы интерфейса. С.12,14 - отключение сайдбара. С.16,18,38 - отключение подвала. С.20,32 - отключение оригинального блока категорий - он был некрасив, в виде вертикального списка. С.22-31 - код для генерации нового, горизонтального списка категорий.


Скин Tweeki

Skin:Tweeki
GitHub
OffSite - там документация по тонкой настройке.

Простой, красивый, но вместе с тем весьма гибкий в настройке. Пока стал основным.

Изменения пока таковы (includes/TweekiTemplate.php):

146c146
<               $contentclass .= ' ' . wfMessage( 'tweeki-container-class' )->escaped();
---
>               $contentclass .= ' ' . wfMessage( 'tweeki-container-class_DISABLED' )->escaped();
790c790
<               if( !wfMessage( 'tweeki-subnav' )->isDisabled() && $this->checkVisibility( 'subnav' ) ) { ?>
---
>               if( true or !wfMessage( 'tweeki-subnav' )->isDisabled() && $this->checkVisibility( 'subnav' ) ) { ?>
897,902c897,948
<                       <?php if ( $this->checkVisibility( 'firstHeading' ) ) { ?>
<                       <h1 id="firstHeading" class="firstHeading page-header" lang="<?php
<                               $this->data['pageLanguage'] = $this->getSkin()->getTitle()->getPageViewLanguage()->getHtmlCode();
<                               $this->text( 'pageLanguage' );
<                       ?>"><span dir="auto"><?php $this->html( 'title_formatted' ) ?></span></h1>
<                       <?php } ?>
---
>
>
> <style>
> /* Dropdown Button */
> .dropbtn {
> ##  background-color: #04AA6D;
> @@  color: white;
>   padding: 16px;
>   font-size: 16px;
>   border: none;
> }
>
> /* The container <div> - needed to position the dropdown content */
> .dropdown {
>   position: relative;
>   display: inline-block;
> }
>
> /* Dropdown Content (Hidden by Default) */
> .dropdown-content {
>   display: none;
>   position: absolute;
>   background-color: #f1f1f1;
>   min-width: 160px;
>   box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
>   z-index: 1;
> }
>
> /* Links inside the dropdown */
> .dropdown-content a {
>   color: black;
> #  padding: 12px 16px;
> #  text-decoration: none;
> #  display: block;
> }
>
> /* Change color of dropdown links on hover */
> .dropdown-content a:hover {background-color: #ddd;}
>
> /* Show the dropdown menu on hover */
> .dropdown:hover .dropdown-content {display: block;}
>
> /* Change the background color of the dropdown button when the dropdown content is shown */
> ##.dropdown:hover .dropbtn {background-color: #3e8e41;}
>
> </style>
>
>
> <!--                  <h1><span dir="auto"><?php $this->html( 'title_formatted' ) ?></span></h1>
>                       <div id="tweekiTOC"></div>
>
>
904a951,975
>
>
> <div style="border: 0px solid red; width=40px; height: 100px;">
>   <div style="float:left;">
>                       <h1><span dir="auto"><?php $this->html( 'title_formatted' ) ?></span></h1>
> <?php
>                       if( $this->data['language_urls'] ) { ?>
> <div class="dropdown">
>   <button class="dropbtn"><?php $this->msg('otherlanguages') ?></button>
>   <div class="dropdown-content">
> <?php
> foreach($this->data['language_urls'] as $key => $langlink):
>  echo $this->makeListItem($key, $langlink);
> endforeach;
> ?>
>   </div>
> </div>
> <?php } ?>
>   </div>
>   <div style="float:right;">
>                       <div id="tweekiTOC"></div>
>   </div>
> </div>
> <br clear=all>
>


С.2,4 - расширение блока контента на всю ширину страницы. С.6,8 - фикс странного бага с неотображением навбара (см. ниже). С.10-15 - отключение показа адреса вики-страницы под тайтлом страницы.. непонятно что это вообще такое и как правильно его отключать. С.17-94 - разные новшества:

19-62 - стили для выпадающей менюшки выбора языка
72-86 - див для горизонтального размещения поддивов с тайтлом + меню языка и TOC страницы. Сделано так, потому что инфобокс стоит на уровне осн. текста, а тайтл не является его частью и смещает текст и инфобокс вниз. В результате над инфобоксом оставалось пустое неиспользованное пространство.
74 - Модифицированный тайтл (вместо удаленного из 10-15).
75-84 - код генератора ссылок интервики (использует стили 19-62).

В основном конфиге вики добавлены параметры:

wfLoadSkin( 'Tweeki' );
$wgTweekiSkinHideable[] = 'sidebar-right';
$wgTweekiSkinHideAnon['EDIT-EXT'] = true;
$wgTweekiSkinHideAnon['subnav'] = true;
$wgTweekiSkinHideAnon['subnav'] = true;
$wgTweekiSkinUseTooltips = true;
$wgTweekiSkinHideAll['footer-info'] = true;
$wgTweekiSkinHideLoggedin['footer-custom'] = true;
$wgTweekiSkinHideable = [ 'firstHeading' ];
$wgTweekiSkinCustomEditSectionLink = false;

Также создан стиль скина MediaWiki:Tweeki.css:

/* CSS placed here will affect users of the Tweeki skin */
a.new, a.new:visited {
  cursor: text !important;
  color: black;
  text-decoration: none;
  pointer-events: none;
//  opacity: 0.6;
}

Эти параметры "отключают" ссылки на несуществующие страницы - настраивают стиль ссылок как обычный текст. БАГ - не удается переключить курсор в текстовый - несмотря на cursor: text !important; курсор остается стрелочкой..

Иконки для ссылок

TODO: Разобраться с логотипом и шапкой. Прикрутить иконки для ссылок. Взять их из MediaWiki:Common.css. Внесение кода в MediaWiki:Tweeki.css не сработало. Add_custom_CSS тоже не сработало.

Получилось добраться через skins/Tweeki/public/legacy/css/externallinks.less. Там немного др. формат для ссылок. Проблема: где-то жостко зашито, что выше каталога skins подыматься нельзя. И images/e/e1/Gmaps16dp.png по факту превращается в /skins/Tweeki/public/legacy/css/images/e/e1/Gmaps16dp.png


Еще попробовать измененный формат в MediaWiki:Tweeki.css

skins/Tweeki/includes/Hooks.php:110 -

// load external link styles
if( $config->get( 'TweekiSkinUseExternallinkStyles' ) ) {
$styles[] = 'skins.tweeki.externallinks.styles';

Вопрос решился немного по молдавански, но зато работает: Из MediaWiki:Common.css взят код иконок и помещен в MediaWiki:Tweeki.css с изменением формата (.mw-parser-output a[href^="https://lahwiki.sphynkx.org.ua/"].external => #content a.external[href^="https://lahwiki.sphynkx.org.ua/"]). Также сделан софтлинк /images в /skins/Tweeki/public/legacy/css.


Прописанные в LocalSettings.php параметры $wgLogos не работают. В соответствии с рекомендациями логотип уменьшен до 40px, загружен (как Файл:Lahwiki pyr01 40px.png) и прописан в MediaWiki:Tweeki-navbar-brand (без разметки).

TOC

Оригинальный TOC отключен - он появлялся в левом или правом столбце, делая страницу некомпактной и некрасивой. Поэтому столбцы отключены (в MediaWiki:Tweeki-sidebar-left и MediaWiki:Tweeki-sidebar-right убрано все содержимое). В TweekiTemplate.php с. 899 добавлен код:

                        <div id="tweekiTOC"></div>

что выводит ТОС прямо под тайтлом страницы (примерно как и было в скине modern).

Модификация модуля Videogallery

В код Модуль:Videogallery внедрена проверка существования страницы субтитров. Если не существует - отрабатывает span class="tech" и в пуб.режиме слово субтитры вообще не отображается. Проверка реализована средствами вики (с помощью #ifexist) - так оказалось проще: в get_embed(u):

                                    ytid = '<span class="'.. '{{#ifexist: Субтитры:'.. id .. ' | | tech }}' .. '"><br>[[Субтитры:' .. id .. '|(Субтитры)]]</span>'

в format_embed(d, u, t, c):

     ytid = '<br><span class="tech" style="color: lightgray;">(Без субтитров)</span>'

Шаблон TODO

Данный шаблон позволяет вставлять в тело страницы небольшой блок с заголовком "Что еще надо сделать" и принимает в качестве параметра текст (описание, что именно надо сделать). Сугубо технический инструмент-подсказка, хорошо заметная на странице. Естественно, что на пуб.сайте этот блок отображаться не должен. Поэтому код шаблона был модифицирован - добавлен класс tech. В MediaWiki:Tweeki.css добавлено определение класса:

.tech
{
  display: none;
}

Ссылки на эту страницу

Данный инструмент встроен в формат страниц неймспейса Субтитры:. Для каждой страницы в спискссылающихся страниц добавляет еще и ссылки на редактирование этих страниц. К счастью, блок этих ссылок охвачен тегом с класом mw-whatlinkshere-tools. Чтобы скрыть его, надо добавить в MediaWiki:Tweeki.css параметр скрытия (как для tech). А можно и проще - добавить к tech:

.tech, mw-whatlinkshere-tools
{
  display: none;
}

Панель subnav

Схема страницы для скина

Эта панель расположена под панелью navbar (там где логотип) и над тайтлом страницы.

Сначала подключаем элементы панели: в MediaWiki:Tweeki-navbar-class впмсываем:

navbar navbar-default navbar-fixed-top navbar-expand-lg fixed-top navbar-light bg-light

(наверняка там что-то лишнее..). Появляется сероватая секция, на которой расположен логотип и элементы меню текущего юзера и настроек. Их отключаем в LocalSettings.php:

$wgTweekiSkinHideAll = [ 'PERSONAL' => true , 'TOOLBOX' => true];

Затем в MediaWiki:Tweeki-subnav вносим названия нужных страниц - без форматирования, по одной в строке. В частности были введены некоторые страницы, присутствующие в сайдбаре. В результате сайдбар в пуб.сайте отключен, но доступно меню сверху с некоторыми его элементами, и это настраиваемо.

!! В сайдбаре в основном указаны страницы-категории, поэтому для нужных страниц надо их создать и сделать редиректы на соотв.категории..

Custom Footer

Появилась необходимость вывести в подвале ссылку на инфу о правах и приватности.. Предлагаемыми методами сделать это почему-то не удалось. Как вариант - штатный метод движка, но он не пробовался. Получилось так: создана страница MediaWiki:Tweeki-footer и в ней текст: Help:Privacy policy|Privacy policy. При этом ссылка на Privacy policy появилась внизу слева. По ссылке создана страничка с текстом.

Решено делать не ссылку на отд.страничку, а разместить текст прямо в футере. Возникла проблема - MediaWiki:Tweeki-footer интерпретирует размещенный текст как гиперссылку, а запятую - как разделитель гиперссылок. Поэтому придуман трюк - текст начинается с | а запятые заменяются на &#44;.

TODO: Надо продублировать в en и оставить англ. и рус. варианты каждый в своей версии. Также подумать о создании отд.неймспейса, чтобы не светить Help. Добавить эти страницы в whitelist. Создан неймспейс Policy и в нем странички, доступные по адресам https://lahwiki.sphynkx.org.ua/Policy:Privacy_policy и https://en.lahwiki.sphynkx.org.ua/Policy:Privacy_policy

Hide file history table

На страничках файлов отображается таблица с истроией правки файла, указанием времени и автора. Эта инфа посчиталась чувствительной и была скрыта добавлением такого определения в MediaWiki:Tweeki.css:

/*Hide file history table in file pages*/
#mw-imagepage-section-filehistory
{
  display: none;
}

Однако скрыть заголовки История файла и линку Загрузить новую версию этого файла не удалось.

Поддержка другого субдомена (вики-ферма)

Для корректной работы скина в др. поддомене необходимо создать/отредавтировать все страницы в неймспейсе MediaWiki. Теоретически. На практике возникли проблемы:

  • Логотип в шапке не отображается. Только текстом имя файла, введенное в MediaWiki:Tweeki-navbar-brand Вопрос решился перезаливкой файла в en.
  • Список страниц из MediaWiki:Tweeki-subnav не отображается.
  • Созданный MediaWiki:Tweeki.css создался как обычная страница. И соотв. стили из него не работают. Заработало после добавления дубликатов параметров скина из LocalSettings_en.php в LocalSettings_en.php:
wfLoadSkin( 'Tweeki' );
$wgTweekiSkinPageRenderer = 'self::renderPage'; ## https://tweeki.kollabor.at/wiki/Configuration_Options#Page_Layout
$wgTweekiSkinHideable[] = 'sidebar-right';.
$wgTweekiSkinHideAnon['EDIT-EXT'] = true;..
##$wgTweekiSkinHideAnon['subnav'] = true;
$wgTweekiSkinUseTooltips = true;
$wgTweekiSkinHideAll['footer-info'] = true;
$wgTweekiSkinHideLoggedin['footer-custom'] = true;
##$wgTweekiSkinHideable = [ 'firstHeading' ];
$wgTweekiSkinCustomEditSectionLink = false;
############# not workx: ####
$wgTweekiSkinSpecialElements = [
#  'FIRSTHEADING' => 'self::renderFirstHeading',.
#  'TOC' => 'self::renderTOC',.
  'SEARCH' => 'self::renderSearch',.
#  'LOGO' => 'self::renderLogo',.
#  'LOGIN-EXT' => 'self::renderLoginExt'.
  ];

$wgTweekiSkinHideAll = [ 'PERSONAL' => true , 'TOOLBOX' => true]; ## hide current user and tools menu

Баг с subnav

Обнаружился совершенно непонятный баг. В двух виках из одной вики-фермы, с идентичными настройками, в базовой вике навбар отображается как положено. Тогда как в en - ни коим образом не хочет. Пришлось захардкодить (TweekiTemplate.php:790):

<                if( !wfMessage( 'tweeki-subnav' )->isDisabled() && $this->checkVisibility( 'subnav' ) ) { ?>
>                if( true or !wfMessage( 'tweeki-subnav' )->isDisabled() && $this->checkVisibility( 'subnav' ) ) { ?>


Блок категорий в футере

Внезапно обнаружилось, что скин не выводит список подключенных категорий. Различные рекомендации почему-то не заработали, пришлось дописать код в skins/Tweeki/includes/TweekiTemplate.php:

946a1018,1040
>
>
>  <?php
> $title = $this->data['skin']->getTitle();
> $categories = $title->getParentCategories();
> if ($categories) {
> $catcnt = count($categories);
>     echo '<div id="catlinks2" class="mw-normal-catlinks" data-mw="interface"><b><a href="/' .
>       SpecialPage::getTitleFor( 'Categories' ) .
>       '">' .
>       MediaWikiServices::getInstance()->getSpecialPageFactory()->getLocalNameFor('Categories' ) .
>       ':</a></b><br>';
>
>     foreach ( $categories as $cat => $_) {
>       $catcnt--;
>       echo"<a href='/$cat'>", preg_replace("/.*?\:/","", $cat),"</a>";
>       if ($catcnt){echo '; ';}else{echo '';}
>       }
>     echo "</div><p></p>";
> }
> ?>

Тут в с.8 вычисляется размер массива категорий, далее это значение декрементится (с.16) и используется для вставки ; только после нефинальной категории (с.18). С.9-13 - формирование локализованного слова "Категории" (вытаскиваем из имени спецстраницы). В с.9 в div id="catlinks2" поставлена двойка, т.к. без нее блок категорий пропадал. Почему там - не стал заморачиваться.

В результате все красиво - локализировано и расположено в сереньком блоке футера, над текстом объявления.

Миграция вики

Переезд осуществляется переносом файлов в /var/www/wiki/images и миграцией страниц. Предварительно в новом вики-движке надо установить и подключить все расширения, которые были подключены в старой вики - расширения могу добавлять поля в таблицах БД, которые в новой вике по умолчанию отсутствуют. Также надо перенести и параметры тонкой настройки (напр. $wgMaxArticleSize).. Вообще, желательно привести конфиги к максимально идентичному виду.

Прецедент при настройке ВикиФермы (см.ниже).. Расширение DPL, если оказалось подключенным к чистой вике, может вызвать рекурсивный вызов страницы, приводящий к ошибке вывода (с попыткой переадресации на несуществующий шаблон). Если такое случится - до переноса расширение закомментить. !!! Нв момент раскомменчивания расширения, вика должна быть открытой - иначе не смогут создаться необходимые расширению шаблоны. После прогрузки какой-то странички, использующей DPL, оно донастроится и затем, при желании, вику можно снова закрыть.

Миграция страниц

В простейшем случае экспорт и импорт страниц можно сделать через веб-интерфейс: Служебная:Экспорт и Служебная:Импорт. На странице экспортирования в старой вике генерируем xml-файл дампа всех (или выборочно) страниц. Затем в новой незаполненной еще вики через страницу импорта загружаем этот файл, отмечаем "Связать правки с локальными участниками..". В качестве "Префиксы интервики" - любой символ. Метод удобен и работает в случае небольших объемов и размера дампа несколько Мб. Гигабайтный дамп уводит сервер в таймаут, причем не помогает увеличение лимитов на размеры и ожидание ПОСТ-запросов. В этом случае удобнее экспорт и импорт делать штатными скриптами. Если в старой вике увеличивали макс.размер статьи - его также надо увеличить и в новой (иначе импорт будет отваливаться с ошибкой):

$wgMaxArticleSize = 2048000;

Экспорт mantainance-скриптом (долго):

php /usr/share/mediawiki/maintenance/dumpBackup.php -- conf /usr/share/mediawiki/LocalSettings_mycustomconfig.php --full > fulldump.xml

Импорт mantainance-скриптом (еще дольше):

php /usr/share/mediawiki/maintenance/importDump.php --conf /usr/share/mediawiki/LocalSettings_mycustomconfig.php --username-prefix="" < fulldump.xml

После чего скрипт предложит проапдейтить вику:

php /usr/share/mediawiki/maintenance/rebuildrecentchanges.php --conf /usr/share/mediawiki/LocalSettings_mycustomconfig.php
php /usr/share/mediawiki/maintenance/initSiteStats.php --conf /usr/share/mediawiki/LocalSettings_mycustomconfig.php

Миграция файлов

Файлы копируются в новое расположение. Если в настройках веб-сервера новой вики поменялся владелец процесса (либо изменился его userid - проверить в /etc/passwd), возможно придется сменить владельца файлов и каталогов:

chown -r newowner:newgroup /var/www/wiki/images

Переезд на Veda.Wiki

Под публичный сервис закуплен хостинг под ВМку и доменное имя veda.wiki. Совокупность всех сервисов приведена в максимальное соответствие - на сервере проведен апгрейд системы и вики-движка до версий, соотв. таковым на новом серваке (Fedora: 38 => 40, Mediawiki 1.39 => 1.40). Проверена работоспособность всех систем. Предполагается, что старый сервер (lahwiki.sphynkx.org.ua) останется в качестве девелопмент-сервера, для проб и отладки нововведений. Который по мере готовности потом будут переноситься на новый (veda.wiki).


Подготовка нового сервера.

На сервере отрыты порты 80 и 443:

firewall-cmd --zone=public --permanent --add-port=80/tcp 
firewall-cmd --zone=public --permanent --add-port=443/tcp 
firewall-cmd --reload

настроена авторизация по ключам. Так же сменен дефолтный пароль рута. Далее установлены nginx, php-fpm и letsencrypt, создан тестовый домен, настроен https, проверена работа и доступность извне тестового сайта.

Сначала установлен движок Mediawiki. Он оказался уже с версией 1.41. Настроена тестовая вика с тестовой БД my_wiki (в последствии можно удалить):

mkdir /var/www/wiki
dnf install nginx php php-fpm mediawiki php-intl php-pecl-apcu php-mysqlnd php-pear-MDB2-Driver-mysqli mariadb mariadb-server rsync

Создаем конфиг для тестовой вики /ect/nginx/conf.d/vedawiki.conf и рестартим nginx.

systemctl enable nginx
systemctl enable php-fpm
service nginx restart

Проверяем работу веб-сервера. Затем настраиваем сертификаты домена (в F40 letsencrypt как-то хреново работает - пришлось прикручивать сертификаты вручную):

service nginx stop
letsencrypt ## oops, in this system it cannot conf domains..
certbot certonly ## choose option 1. Then copy-paste ssl-options from other subdomains, modify paths..
nginx -t
service nginx restart

Настраиваем БД:

systemctl enable mariadb
systemctl start mariadb
mysql_secure_installation

И отвечаем на некоторые вопросы :

Switch to unix_socket authentication [Y/n] n
Change the root password? [Y/n] y
Remove anonymous users? [Y/n] y
Disallow root login remotely? [Y/n] y
Remove test database and access to it? [Y/n] y
Reload privilege tables now? [Y/n] y

Проверяем:

mysql -u root -p

Зайдя создаем тестовую БД для вики:

CREATE DATABASE my_wiki;
GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY '********';
GRANT ALL PRIVILEGES ON my_wiki.* TO 'root'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
QUIT;

Заходим на https://veda.wiki и запускаем установку. Закидываем сгенеренный LocalSettings.php в /usr/share/mediawiki, софтлинкаем:

ln -s /usr/share/mediawiki/LocalSettings.php /var/www/wiki/



Переезд Mediawiki

Перенос файлов

На стороне старого сервера запускаем команды:

rsync -a -v -v /var/www/wiki root@79.174.85.192:/opt

Тут можно было адресовать сразу в /var/www т.к. софтлинки все равно залились относительно корня.. rsync обращается к rsync на удаленной стороне, поэтому он там уже должен быть установлен. Не все доехало, в частности скины (ошибок не было, но возможно изза того что в Tweeki есть софтлинк на виковский images). Поэтому дополнительно еще так:

rsync -a -v -v /usr/share/mediawiki root@79.174.85.192:/opt

и потом уже раскидать все по своим местам.

Перенос БД

На старом сервере делаем:

mysqldump lah_wiki -uroot > lah_wiki_en.sql
mysqldump lah_wiki -uroot > lah_wiki.sql

а затем:

rsync -a -v -v -z lah_wiki_en.sql root@79.174.85.192:/opt
rsync -a -v -v -z lah_wiki.sql root@79.174.85.192:/opt

Потом на новом серваке:

mysql -u root -p

И..

CREATE DATABASE lah_wiki;
CREATE DATABASE lah_wiki_en;
GRANT ALL PRIVILEGES ON lah_wiki.* TO 'root'@'localhost' WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON lah_wiki_en.* TO 'root'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
QUIT;

И..

mysql -u root -p lah_wiki_en < /opt/lah_wiki_en.sql
mysql -u root -p lah_wiki < /opt/lah_wiki.sql

Далее заменяем временный LocalSettings.php на таковой со старого сервака. Комментим в нем секции LDAP и вики-фермыText, секцию вики-фермы оборачиваем конcтрукцией if ( isset( $_SERVER['SERVER_NAME'] ) ) { .. } - чтобы maintanance-скрипты не ругались на необъявленную переменную. Также (при надобности) раскомменчиваем секцию дебага. В переменной $wgServer меняем домен на "https://veda.wiki". Вика начинает открываться но плохо - все страницы считает отсутствующими. Надо проапдейтить БД:

maintenance/run update

Апдейт падает сетуя на удаление несуществующих таблиц:

Table templatelinks contains tl_title field. Dropping...Wikimedia\Rdbms\DBQueryError from line 1236 of /usr/share/mediawiki/includes/libs/rdbms/database/Database.php: Error 1091: Can't DROP INDEX `tl_namespace`; check that it exists
Function: Wikimedia\Rdbms\Database::sourceFile( /usr/share/mediawiki/maintenance/archives/patch-templatelinks-drop-tl_title.sql )
Query: DROP  INDEX tl_namespace ON  `templatelinks`

Закомментариваем в maintenance/archives/patch-templatelinks-drop-tl_title.sql все строки и перезапускаем апдейт. Теперь вика нормально работает. Из замеченного - перестали окрашиваться зеленым редиректы.. Но это это оказались глюки кеширования.

По аналогии все эти манипуляции проделаны и для англ.версии.

DPL в новой версии снова начал капризничать и игнорировать исключения категорий. Нестабильное поведение сподвигло к поиску решения на основе других средств. Найден подходящий экстеншн wiki/Extension:Newest_Pages, выдающий списки страниц по неймспейсу или юзеру. Название не совсем корректное - экстеншн не использует таблицу recentchanges и выдает все страницы вне зависимости от даты правки. Экстеншн переделан с целью вывода в 3 колонки, в стиле категорий (подзаголовки из первых букв). Также написан генератор TOCа, генерирующий список только из имеющихся символов. К моменту дописания выяснилось, что прежний DPL-список перестал глючить и заработал как ранее.. но было поздно. Новое решение лучше и быстрее, за списком страниц обращается непосредственно к БД.

Экстеншны

Некоторыйе экстеншны начали плохо работать и их пришлось также проапдейтить до версий, соответствующих медиавики 1.42. Для удобства отладки распакованы разные версии и сделаны софтлинки на нужные. Обновлялись: DynamicPageList3, LDAPAuthentication2, LDAPAuthorization, LDAPGroups, LDAPProvider, LDAPUserInfo, PageInCat, Translate, UniversalLanguageSelector.

LDAP

LDAP воспроизведен по имеющемуся мануалу и заработал без проблем. Возникли сложности с настройкой медиавики, но это оказалось следствием работы механизмов кеширования движка и броузеров.

Настройка WikiFarm

ВикиФерма - хостинг нескольких вики совместно на одном коде установленной mediawiki. Переключение вик происходит посредством обработки переменной $_SERVER['SERVER_NAME'] приходящей от веб-сервера - в LocalSettings.php оператор switch подключает конфиг нужной вики. Недостатки метода: движок и все плагины общие, жестко привязаны к одной и той же версии; картинки и загружаемые файлы хранятся совместно и если потом придется одну из вик вывести из фермы, последующая зачистка ее файлов будет представлять проблему (возм., решается в конфигах - установкой разных каталогов для аплоада - надо проверить).

Предполагается, что домены настроены и все нужные пакеты установлены.. (letsencrypt: при выборе типа редиректа выбираем 2 - Redirect) Сначала ставим первую вику - как обычно. Создаем базу - запускаем mariadb -uroot -p и выполняем команды:

CREATE DATABASE my_wiki;
GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY '<PASSWORD>';
GRANT ALL PRIVILEGES ON my_wiki.* TO 'root'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;

Теперь заходим на https://wiki.sphynkx.org.ua/ производим установку и настройку следуя рекомендациям. Сгенерированный конфиг переименовываем в LocalSettings_mywiki.php и помещаем в /usr/lib/mediawiki Там же создаем LocalSettings.php с кодом примерно таким:

LocalSettings.php:

<?php
// Include common settings to all wikis before this line (eg. database configuration)

        switch ( $_SERVER['SERVER_NAME'] ) {
                case 'wiki_tpl.sphynkx.org.ua':
// not exist - template only
//                        require_once 'LocalSettings_tpl.php';
//                        break;

                case 'wiki.sphynkx.org.ua':
                        require_once 'LocalSettings_mywiki.php';
                        break;

                case 'sociowiki.sphynkx.org.ua':
                        require_once 'LocalSettings_sociowiki.php';
                        break;

                case 'astrowiki.sphynkx.org.ua':
                        require_once 'LocalSettings_astrowiki.php';
                        break;

                case 'artwiki.sphynkx.org.ua':
                        require_once 'LocalSettings_artwiki.php';
                        break;

                case 'cvwiki.sphynkx.org.ua':
                        require_once 'LocalSettings_cvwiki.php';
                        break;

                default:
                        header( 'HTTP/1.1 404 Not Found' );
                        echo 'This wiki is not available. Check configuration.';
                        exit( 0 );
        }

В принципе, эту первую вику можно использовать как шаблон для остальных. Далее настраиваем следующую, к примеру cvwiki. Опять создаем базу:

CREATE DATABASE cv_wiki;
GRANT ALL PRIVILEGES ON cv_wiki.* TO 'root'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;

Поскольку уже существует /usr/lib/mediawiki/LocalSettings.php и у него содержимое, не совсем понятное для инсталлятора - https://wiki.sphynkx.org.ua/ выдаст ошибку. Надо задать полный путь - https://wiki.sphynkx.org.ua/mw-config/index.php Полученный конфиг можно не сохранять, а вместо этого скопировать LocalSettings_mywiki.php в LocalSettings_cvwiki.php и поправить значение имени базы, логина, пароля, УРЛа, имени вики.

Далее по аналогии. Для удобства можно софтлинкнуть конфиги в /var/www/wiki

Install issues

При установке и настройке очередного инстанса фермы могут возникнуть неприятности с DPL - см.#DPL install issue. Вкратце - надо временно отключить закрытость вики для того чтобы DPL создал необходимые шаблоны. И потом закрыть опять.

Также возникали проблемы с экстеншном ShortUrl. Его надо подключить повторно в конфиге новой вики и затем произвести настройку таблиц БД:

php /usr/share/mediawiki/extensions/ShortUrl/maintenance/populateShortUrlTable.php --conf /usr/share/mediawiki/LocalSettings_en.php

Однако populateShortUrlTable.php почему-то решил не находить maintenance/Maintenance.php (хотя раньше работало). Пришлось поправить:

#require_once "$IP/maintenance/Maintenance.php";
require_once "/usr/share/mediawiki/maintenance/Maintenance.php";

Затем в новом конфиге ShortUrl можно отключить.


Upload Dir

Для каждой вики-фермы настроены отдельные каталоги загружаемых файлов. В LocalSettings.php каждого сайта фермы прописываем свой каталог, по типу:

$wgUploadDirectory = "{$IP}/images_cvwiki";

Конкретно в случае Федоры, каталоги по факту создаем в /usr/share/mediawiki и софтлинкаем в /var/www/wiki.

Однако возникла проблема при отображении реальных файлов - они по-прежнему указывают на каталог images. Рекомендуется настроить алиас в nginx. Там в стандартной конфигурации субдомена Вики есть раздел location /images в который добавляем алиас в начало:

    location /images {
    # Separate location for images/ so .php execution won't apply

      alias /var/www/wiki/images_cvwiki;

и перезапускаем nginx.

Общие таблицы для 2 вик

https://www.mediawiki.org/wiki/Manual:Shared_database

В контексте организации 2й вики для др.языка возникла идея использовать в ней некоторые таблицы из базовой вики. В частности - картинки, но сохраняя свой комплект страниц, шаблонов.. Такие вещи делаются в конфиге 2й вики так:

$wgSharedDB  =  'lah_wiki' ;
$wgSharedTables = [
    'image',
    'imagelinks',
    'oldimage',
    'actor',
#    'page',
    'user',
    'user_properties',
    'user_autocreate_serial',
];

Однако выяснилось, что картинки так расщарить не удастся. Картинки хранятся в БД как и др.вики-страницы (но указывается др.неймспейс). Т.е. надо тогда экспортировать и таблицу page. Но базовая page не объединяется, а перекрывает таблицу 2й вики и становятся недоступными все ее страницы. Похоже, придется строить все в базовой ДБ.

https://www.mediawiki.org/wiki/Manual:$wgForeignFileRepos

Удалось сделать это вот такой магией в LocalSettings_en.php:

$wgRepositoryBaseUrl = 'https://lahwiki.sphynkx.org.ua/File:';
$wgUseSharedUploads = true;

$wgForeignFileRepos[] = [
    'class' => ForeignDBRepo::class,
    'name' => 'lah',
    'url' => "https://lahwiki.sphynkx.org.ua/images",
    'directory' => '$wgScriptPath/images',
    'hashLevels' => 2, // This must be the same for the other family member
    'dbType' => $wgDBtype,
    'dbServer' => $wgDBserver,
    'dbUser' => $wgDBuser,
    'dbPassword' => $wgDBpassword,
    'dbFlags' => DBO_DEFAULT,
    'dbName' => 'lah_wiki',
    'tablePrefix' => '',
    'hasSharedCache' => false,
    'descBaseUrl' => 'https://lahwiki.sphynkx.org.ua/File:',
##    'thumbScriptUrl' => "$wgScriptPath/thumb.php",
    'thumbUrl' =>'$wgScriptPath/images/thumb',
    'thumbScriptUrl' => "https://lahwiki.sphynkx.org.ua/thumb.php",
    'fetchDescription' => true ##false
];

Данные настройки позволяют использовать картинки и превьюшки, обращаясь к базовой БД, тогда как для всех остальных страниц используется отдельная БД lah_wiki_en.

Единственный обнаруженный пока баг - ссылка на картинку типа https://en.lahwiki.sphynkx.org.ua/thumb.php?f=Shkatulka-v-forme-rakoviny-iz-piramidy-sehemheta.jpg&width=170 выдает Error generating thumbnail The source file 'Shkatulka-v-forme-rakoviny-iz-piramidy-sehemheta.jpg' does not exist., тогда как в базовом хосте (без en) нормально показывает картинку. Но на отображении и остальной работе не отражается.

Настройка интервики

Экстеншн Интервики уже есть в комплекте и надо его подключить.

wfLoadExtension( 'Interwiki' );
$wgGroupPermissions['sysop']['interwiki'] = true;

Затем идем на спецстраницу Служебная:Интервики и жмем "добавить новый префикс". Открывается страничка, на которой для en вписываем УРЛ https://en.lahwiki.sphynkx.org.ua/$1 и ставим галку на Перенаправлении.

Тоже самое делаем и со второй викой (en). Подключаем в ее кофиге (если не наследовано из базового), идем на спецстраницу Special:Interwiki, вписываем УРЛ https://lahwiki.sphynkx.org.ua/$1 и ставим галку на Forward.

Теперь обе вики могут ссылаться друг на друга. Теперь надо поставить в соответствие страницы из разных языков. Делается внутренними ссылками (которые на странице не отображаются). Ссылки можно ставить в любом месте. На страницах базовой вики ставим ссылки в таком формате:. Тода как в en на странице Page ставим ru:Страница.

Не все скины умеют выводить ссылки интервики. Некоторые надо доработать. У движка Медиавики есть средства. Вот так выводится список ссылок на языки:

foreach($this->data['language_urls'] as $key => $langlink):
 echo $this->makeListItem($key, $langlink);
endforeach;

$this->msg('otherlanguages') - тут хранится фраза "На других языках" (с локализацией).

Ниже будет внесенный код для организации выпадающего меню со списком языков.

Оптимизация конфига Nginx

Для доп.субдомена необходим отдельный конфиг с секцией server{..} идентичной, за исключением нескольких параметров. Поэтому общая часть была вынесена в отд.файл (/etc/nginx/sites-available/lahwiki.base) и может подключается к разным языковым субдоменам. Базовый домен теперь выглядит так:

server {
    server_name lahwiki.sphynkx.org.ua;
    listen 9595;

    root /var/www/wiki;
    index index.php index.html index.htm;
    autoindex off;

    access_log /var/log/nginx/lahwiki-access.log;
    error_log /var/log/nginx/lahiki-error.log;

include /etc/nginx/sites-available/lahwiki.base;

}

Домен en аналогично, но другие server_name, listen и имена логфайлов.

Wiki Translation

Для организации процесса перевода страниц в пределах одной вики удобен экстеншн Extension:Translate. Он позволяет отслеживать изменения исходных страниц и сообщать о необходимости коррекции в переводах, выводит статистику, предоставляет интерфейс для работы переводчиков. Но предназначен он только для переводов в пределах одной вики. Переводимые страницы помещаются в субстраницы с именем в виде кода языка, напр.: Страница/en. Подключение другой вики в экстеншне не предусмотрено. Можно наверное сделать импорт через XML и периодически запускать скриптом.. но это кривое решение. Можно использовать получаемую страницу с переводом как черновик и потом вручную переносить переведенный контент в др. вику.

Настройка заключается в установке нескольких взаимозависимых экстеншнов: Extension:Translate, Extension:UniversalLanguageSelector и Extension:CLDR

В LocalSettings.php прописываем:

wfLoadExtension( 'UniversalLanguageSelector' );
wfLoadExtension( 'cldr' );
wfLoadExtension( 'Translate' );
$wgCacheDirectory = "$IP/cache";
$wgGroupPermissions [ 'translator' ][ 'translate' ]  =  true ;
$wgGroupPermissions [ 'translator' ][ 'skipcaptcha' ]  =  true ;
$wgGroupPermissions [ 'sysop' ][ 'pagetranslation' ]  =  true ;

После этого вика падает, потому что экстеншн не смог создать нужные таблицы. Делаем это вручную:

cd extensions/Translate/sql/mysql
mysql -u root -p lah_wiki_en < revtag.sql
mysql -u root -p lah_wiki_en < translate_cache.sql
mysql -u root -p lah_wiki_en < translate_groupreviews.sql
mysql -u root -p lah_wiki_en < translate_groupstats.sql
mysql -u root -p lah_wiki_en < translate_messageindex.sql
mysql -u root -p lah_wiki_en < translate_metadata.sql
mysql -u root -p lah_wiki_en < translate_reviews.sql
mysql -u root -p lah_wiki_en < translate_sections.sql
mysql -u root -p lah_wiki_en < translate_stash.sql
mysql -u root -p lah_wiki_en < translate_tm.sql
mysql -u root -p lah_wiki_en < translate_cache-alter-varbinary.sql
mysql -u root -p lah_wiki_en < translate_groupreviews.sql

Затем через Special:UserRights раздаем нужным юзерам права на группу translate. На этом настройки закончены.

Перевод делается так. На желаемой странице идем в редактирование и (в простейшем случае) охватываем весь текст тегами <translate>..</translate>, сохраняемся. Далее в Служебная:Перевод_страниц появляется список страниц для перевода. Выбираем желаемую, она открывается в рабочей среде перевода.. Переводим, публикуем. Перевод окажется в подстранице /en.


Настройка редактора

С помощью Extension:MsWikiEditor можно добавлять свои кнопочки на панель инструментов, а также удалять имеющиеся штатные. Добавляются прописыванием в LocalSettings.php:

wfLoadExtension( 'MsWikiEditor' );
$wgMSWE_add['strike'] = [ 'Strike', '<strike>', 'Text', '</strike>', 'extensions/MsWikiEditor/images/strike.png' ];
$wgMSWE_add['code'] = [ 'Code', '<code>', 'Text', '</code>', 'images/f/f7/Code-icon-176154932-resize32.jpg' ];

Тут для 2й кнопки сделана картинка 32х32, загружена в вику и в параметре установлен путь к ней из сториджа.


Backup system

Самописная система резервного копирования, использующая Telegram в качестве хранилища. Выбор Telegram в этом качестве обусловлен тем, что у него не заявлено каких либо ограничений на количество загружаемых файлов (только на размер каждого - не более 1,5Гб).

Скрипты и файлы

Основной скрипт, управляющий процессом - собирает нужные файлы, дампы и пр., пакует, разбивает на тома и отправляет в Telegram-группу:

lahbkp01.sh:

#!/bin/sh

SYSBKPDIR=/var/www/wiki/_sysbkp
TOUPLOAD=/opt/toupload
APPDIR=$(dirname $0)
NOW=$(date +"%Y-%m-%d")

## 1. Collect nessesary system files
mkdir -p $SYSBKPDIR
mkdir -p $TOUPLOAD
rsync -rR --files-from=$APPDIR/files.list /  $SYSBKPDIR

## 2. Get Technote wikipage and some info about wiki
php /var/www/wiki/maintenance/dumpBackup.php --current --pagelist=$APPDIR/pages.list > $SYSBKPDIR/Technotes.wikitxt
php /var/www/wiki/maintenance/version.php > $SYSBKPDIR/WikiVersion.wikitxt
php /var/www/wiki/maintenance/showSiteStats.php > $SYSBKPDIR/SiteStats.txt
php /var/www/wiki/maintenance/dumpBackup.php --full --quiet > $SYSBKPDIR/lah_full_dump.xml

## 3. Dump LAHwiki DB
mysqldump lah_wiki -uroot > $SYSBKPDIR/lah_wiki.sql

## 4. Archive all and split by volumes
tar chjf $TOUPLOAD/$NOW.tar.bz2 /var/www/wiki
split -b 500M $TOUPLOAD/$NOW.tar.bz2 $TOUPLOAD/$NOW.tar.bz2_part_ -a 4

## 5. Send backups to TG
cd $APPDIR
$APPDIR/sendtotg.py  -t "=============== Start of backup "$NOW" ==============="
for i in `ls $TOUPLOAD/*_part_*` 
    do
	$APPDIR/sendtotg.py $i
    done
$APPDIR/sendtotg.py  -t "=============== End of backup "$NOW" ==============="

## 6. Clean up
rm -rf $TOUPLOAD
rm -rf $SYSBKPDIR

Скрипт отправки в Telegram:

sendtotg.py:

#!/usr/bin/env python
## Based on https://medium.com/@kokhua81/how-to-send-messages-and-files-to-telegram-with-python-66c1abeea7a6
## Script sends file or/and text message to Telegramm Channel from commandline.
## 1. Create app configuration on https://my.telegram.org/apps , get 'api_id' and 'api_hash'
## 2. pip install -r requirements.txt
## 3. At first run the script asks for mobile or UID.. Need send your mobile associated with TG-account, bots access to API is restricted!!
## Subsequently to use backup, download all volumes adn run: cat *_part_* > backup.tar.bz2

import argparse, sys

## Instantiate the config parser
parser = argparse.ArgumentParser(description='''Snippet for tg file upload script..
If args consist path sign or space - doublequote them''')

## Optional positional argument - run without modifiers to upload file
parser.add_argument('filename', type=str, nargs='?', help='Single filename')

## Optional argument - run with modifiers to upload file or/and text (in separate post)
parser.add_argument('-f', '--file', type=str, help='Name of file to upload')
parser.add_argument('-t', '--text', type=str, help='Text to post')

## Without params gets help and quit
args = parser.parse_args(sys.argv[1:])
if len(sys.argv) < 2:
    parser.print_help()
    sys.exit(1)


from telethon import TelegramClient
import asyncio
import configparser

## Load params from config file
config = configparser.ConfigParser()
config.read("config.ini")

## Set variables from config
api_id       = config['Telegram']['api_id']
api_hash     = config['Telegram']['api_hash']
session_name = config['Telegram']['session_name']
channel      = config['TGGroup']['group']


async def func():
    entity = await client.get_entity(channel)
## Choose what we will post - file or/and text
    if args.text:
        await client.send_message(entity=entity, message=args.text)
    if args.filename or args.file:
        filename = args.filename or args.file
        await client.send_file(entity, filename)

## Connection
with TelegramClient(session_name, api_id, api_hash) as client:
    client.loop.run_until_complete(func())

Настройки для Telegram:

config.ini:

[Telegram]
api_id = ********
api_hash = ***************************
session_name = lah_tg

[TGGroup]
group = https://t.me/+IzttN-SZAfo0YmRi

Список файлов и каталогов для бекапа (можно добавлять разные нужные каталоги на свое усмотрение):

files.list:

/etc/nginx/sites-available/lahwiki.conf
/etc/hostname
/etc/fstab
/root/.bash_history
/root/.mysql_history
/usr/local/bin
/opt/lahbkp
/var/spool/cron

Отдельный дамп данной страницы:

pages.list:

Technotes

Необходимые зависимости для Питона:

requirements.txt:

Telethon==1.33.1

Также при работе скрипт создает и использует файл сессии lah_tg.session (база данных в формате sqlite3 - в соответствии с именем, прописанным в config.ini)

Установка

1. Размещаем все файлы в /opt/lahbkp

$ chmod +x *.sh *.py

2. Ставим зависимости для Питона:

$ pip install -r requirements.txt

3. Идем на https://my.telegram.org/apps , регистрируем там новое приложение. В его параметры 'api_id' and 'api_hash' заполняем в свой config.ini. Отрываем приложение Telegram и создаем новый приватный профиль. В его настройках копируем инвайт-линк, вставляем его в свой config.ini.

4. Проверяем работу аплоадера с каналом и работу бекапера целиком:

$ ./sendtotg.py -t "Hello"

При первом запуске скрипт запросит токен бота или номер мобилы, ассоциированный с личным Telegram-аккаунтом. Надо вводить телефон (в международном стандарте - с +), т.к. у бота нет прав на работу с используемыми функциями Telegram API. В Telegram должен прийти системное сообщение с 5-значным кодом - копируем и вставляем в консоль. Если все прошло хорошо - на канале должно появиться новое сообщение с отосланным текстом.

5. Настраиваем mysqldump на работу без запроса пароля - в /etc/my.ini добавляем секцию:

[mysqldump]
user=root
password=<PASSWORD>

Затем запускаем бекапер:

$ ./lahbkp01.sh

Заархивированный бекап оказался весом 8,5Гб и формировался ок. 1,5 часа, разбит на 16 частей по 500Мб. Отправка заняла ок.3 часов. Т.е. полный бекап длится не менее 4,5 часов.

6. Если в группе появились посты с отосланными томами бекапа - значит все работает правильно. Можно настроить задачу в крон на ежемесячный бекап:

0 0 1 * * /opt/lahbkp/lahbkp01.sh


Авторизация LDAP

Было бы неплохо централизовать авторизацию - и для вики, и для возможно других сервисов, с которыми будут работать участники - сформировать некий единый энвайронмент.

Предварительно был сделан снапшот..

virsh snapshot-create-as --domain lah --name "2024_10_22_Works" --description "Before LDAP config"

Предварительные мытарства и полезные фишки

Для истории ..

Configuration of LDAP extension hub

In PLA created roadmin - simple user in root dir, that has r/o access to all tree. Need for ldap search in Extension:LDAPProvider (ldapprovider.json). No need any special user for admin purposes... Password option - clear; shell - NoLogin. Before user the test group was created (in Group) - it need for user creation!! Default request was successful:

ldapsearch -x -W -D 'cn=roadmin,dc=veda,dc=wiki' -b "" -s base -H ldap://192.168.7.27

Created Wiki group in the Group. Created user Test User, added to Wiki group. Created ou=Services and user proxy in it (instead of roadmin). Successful cmd:

ldapsearch -x -W -D 'cn=Test User,ou=People,dc=veda,dc=wiki' -b "" -s base -H ldap://192.168.7.27
ldapsearch -LLL -x -D 'cn=proxy,ou=Services,dc=veda,dc=wiki' -y ~/vldap.txt -H ldap://192.168.7.27 -b 'dc=veda,dc=wiki' cn sn uid

LDAP_Debugging:

$wgDebugLogGroups['PluggableAuth'] = 
$wgDebugLogGroups['LDAP'] = 
$wgDebugLogGroups['MediaWiki\\Extension\\LDAPProvider\\Client'] = 
$wgDebugLogGroups['LDAPProvider'] = 
$wgDebugLogGroups['LDAPGroups'] = 
$wgDebugLogGroups['LDAPUserInfo'] = 
$wgDebugLogGroups['LDAPAuthentication2'] = 
$wgDebugLogGroups['LDAPAuthorization'] = '/tmp/LDAP.log';

..work only for cmdline utils. Not for login form!! And wfDebugLog( 'LDAP', 'XXX'); in LocalSettings.php also..

Command line scripts to verify setup:

# php extensions/LDAPProvider/maintenance/ShowUserInfo.php --domain veda.wiki --username tuser
givenname => Test
sn => User
cn => Test User
uid => tuser
dn => cn=Test User,ou=People,dc=veda,dc=wiki

# php extensions/LDAPProvider/maintenance/ShowUserGroups.php --domain veda.wiki --username tuser
Full DNs:
Short names:

## when "searchattribute" => "uid", "searchstring" => "uid=USER-NAME,ou=People,dc=veda,dc=wiki",
# php extensions/LDAPProvider/maintenance/CheckLogin.php --domain veda.wiki --username tuser
Password:********
FAILED

## when "searchattribute" => "cn", "searchstring" => "cn=USER-NAME,ou=People,dc=veda,dc=wiki",
# php extensions/LDAPProvider/maintenance/CheckLogin.php --domain veda.wiki --username "Test User"
Password:*******
OK

Get members of group:

ldapsearch -H ldap://192.168.7.27 -x -b "dc=veda,dc=wiki" -D "cn=proxy,ou=Services,dc=veda,dc=wiki" -y ~/vldap.txt '(&(objectclass=posixGroup)(memberUid=test.user3))'

Could not preconfigure user prefs for login users - their have set default prefs, and skin for anonymous users (Tweeki). But need set the "modern" authomatically. $wgDefaultUserOptions['skin'] not work - $wgDefaultSkin overrides it. Maybe there will be useful $wgConditionalUserOptions but it will introduced in 1.42.


Проблема с настройкой LDAP аутентификации

Система упорно не хотела настраиваться по непонятным причинам.. Дело оказалось в опечатке, растиражированной во многих мануалах.. В участке настроек авторизации провайдера:

$LDAPProviderDomainConfigProvider = function() {
       $config = [
               'veda.wiki' => [
                       "connection" => [
...

                       ],
                       "groupsync" => [
                               "cn=Wiki_PosixGrp,ou=Group,dc=veda,dc=wiki"
                       ], ## or  cn=Wiki_PosixGrp,ou=Group,dc=veda,dc=wiki
                       "userinfo" => [
                       ],
                       "authorization" => [
                               "rules" => [
                                       "group" => [
                                               "required" => [ "Wiki", "Wiki_PosixGrp" ] ## or Wiki_PosixGrp
                                       ]
                               ]
                       ]
               ],
...

в строке 15 правильное название ключа group, а не groups, как упоминается во могих постах и листингах настроек.

После этого получилось залогиниться ldap-юзером test.user3. Однако позже test.user4 уже не смог - создание пользователя не разрешено. $wgGroupPermissions['*']['createaccount'] = true; не помогло. По рекомендации, решено так: Отключена LDAP-авторизация, локально в вике создан фиктивный пользователь Ldapboss, в любым паролем.. и внесен в группу бюрократов. В ldap был создан настоящий юзер Ldapboss, создан и настроен как положено. Затем в вики снова включена LDAP-авторизация и произведен логин этим пользователем. И затем его логаут. После этого начали автосоздаваться и др. ldap-юзеры. Т.е. для успешного логина новых ldap-юзеров, в системе должен быть один, с правами бюрократа. Однако, тронув настройки, снова перестали создаваться. Похоже, $wgGroupPermissions['*']['createaccount'] = true; все же имеет значение и без него юзер не автосоздается.. Также важно очистить куки - из-за них тоже не удавалось автосоздать юзеров.

Суть "трогания" была в переименовании в LDAP группы Wiki_PosixGrp в Wiki и убирании $wgGroupPermissions['*']['createaccount'] = true; $wgGroupPermissions['Wiki_PosixGrp']['createaccount'] = true;. После возникших проблем возвращено назад.

Ldapboss был удален через mysql:

DELETE FROM `user_groups` WHERE ug_user = 9;
DELETE FROM `user` WHERE user_id = 9;

но это была плохая идея - юзер удалился криво, попытка пересоздания привела к созданию кривому Unknown User.. (Можно использовать Extension:UserManager). Был создан Ldapadm для тех же целей аналогичным образом.


Синхронизация групп

Модификация:

                       "groupsync" => [
//WRK                               "cn=Wiki_PosixGrp,ou=Group,dc=veda,dc=wiki"
"mapping" => ["Wiki_PosixGrp" => "cn=Wiki_PosixGrp,ou=Group,dc=veda,dc=wiki"]
                       ],

начала вносить юзера в локальную группу (была настроена в LocalSettings.php заранее). Теперь надо придумать, как сделать настройки (в частности - скин), общие для всех юзеров группы. Либо - чтоб приезжали от провайдера, каким-нибудь хуком.. Напр. типа такого, or this. Можно соорудить выбор скина на базе Extension:SkinPerNamespace.

Надо еще прикрутить Extension:LDAPSyncAll



LDAP сервер

Ставится штатно по мануалу:

dnf install openldap-servers openldap-clients -y
systemctl enable --now slapd
service slapd restart

Затем командой slappasswd генерируем хеш пароля. Затем создаем .LDIF-файл chrootpw.ldif с содержимым:

# specify the password generated above for [olcRootPW] section
dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcRootPW
olcRootPW: {SSHA}xxxxxxxxxxxxxxxxxxxxxxxxx

И применяем командой:

ldapadd -Y EXTERNAL -H ldapi:/// -f chrootpw.ldif

Также:

ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif

Создаем chdomain.ldif указывая в нем доменное имя для секции dc=veda,dc=wiki и хеш, полученный ранее:

dn: olcDatabase={1}monitor,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth"
  read by dn.base="cn=Manager,dc=veda,dc=wiki" read by * none

dn: olcDatabase={2}mdb,cn=config
changetype: modify
replace: olcSuffix
olcSuffix: dc=veda,dc=wiki

dn: olcDatabase={2}mdb,cn=config
changetype: modify
replace: olcRootDN
olcRootDN: cn=Manager,dc=veda,dc=wiki

dn: olcDatabase={2}mdb,cn=config
changetype: modify
add: olcRootPW
olcRootPW: {SSHA}xxxxxxxxxxxxxxxxxxxxxxxxx

dn: olcDatabase={2}mdb,cn=config
changetype: modify
add: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange by
  dn="cn=Manager,dc=veda,dc=wiki" write by anonymous auth by self write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by dn="cn=Manager,dc=veda,dc=wiki" write by * read

Применяем:

ldapmodify -Y EXTERNAL -H ldapi:/// -f chdomain.ldif

Создаем basedomain.ldif:

# replace to your own domain name for [dc=***,dc=***] section
dn: dc=veda,dc=wiki
objectClass: top
objectClass: dcObject
objectclass: organization
o: Server World
dc: veda

dn: cn=Manager,dc=veda,dc=wiki
objectClass: organizationalRole
cn: Manager
description: Directory Manager

dn: ou=People,dc=veda,dc=wiki
objectClass: organizationalUnit
ou: People

dn: ou=Group,dc=veda,dc=wiki
objectClass: organizationalUnit
ou: Group

и применяем:

ldapadd -x -D cn=Manager,dc=veda,dc=wiki -W -f basedomain.ldif

Настраиваем сертификаты по мануалу. В конец /etc/ssl/openssl.cnf добавляем:

[ veda.wiki ]
subjectAltName = DNS:veda.wiki,DNS:en.veda.wiki,DNS:pma.veda.wiki,DNS:pla.veda.wiki,DNS:mantis.veda.wiki,DNS:lahwiki.sphynkx.org.ua

Генерим:

cd /etc/pki/tls/certs
openssl genrsa -aes128 2048 > server.key

Удаляем passphrase из ключа (будут доп.вопросы по полям, которые можно не заполнять):

openssl rsa -in server.key -out server.key
openssl req -utf8 -new -key server.key -out server.csr

Создаем сертификат со временем жизни 10 лет. В параметре -extensions указываем домен, который вводили в конец /etc/ssl/openssl.cnf:

openssl x509 -in server.csr -out server.crt -req -signkey server.key -extfile /etc/ssl/openssl.cnf -extensions veda.wiki -days 3650
chmod 600 server.key

Настраиваем Slapd для SSL/TLS:

cp /etc/pki/tls/certs/{server.key,server.crt} /etc/openldap/certs/
chown ldap:ldap /etc/openldap/certs/{server.key,server.crt}

Создаем mod_ssl.ldif:

dn: cn=config
changetype: modify
replace: olcTLSCertificateFile
olcTLSCertificateFile: /etc/openldap/certs/server.crt
-
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/openldap/certs/server.key

и применяем его:

ldapmodify -Y EXTERNAL -H ldapi:/// -f mod_ssl.ldif

Перезагружаем сервис и проверяем что все работает:

systemctl restart slapd
ldapsearch -x -b "dc=veda,dc=wiki"
ldapsearch -x -W -D 'cn=Manager,dc=veda,dc=wiki' -b "" -s base -H ldap://127.0.0.1 -d 25

Смена пароля для LDAP админа (Manager)

По мотивам мануала.. Генерим хеш нового пароля

slappasswd -h {SSHA}

Затем создаем newpasswd.ldif в котором меняем на новый хеш

dn: olcDatabase={2}mdb,cn=config
# olcRootDN: cn=Manager,dc=veda,dc=wiki
changetype: modify
replace: olcRootPW
olcRootPW: {SSHA}xxxxxxxxxxxxxxxxxxxxxxxxxx

Применяем, рестартимся, проверяем:

ldapmodify -H ldapi:// -Y EXTERNAL -f newpasswd.ldif
service slapd restart
ldapsearch -H ldap://192.168.7.27 -x -b "dc=veda,dc=wiki" -D "cn=Manager,dc=veda,dc=wiki" -W

Также проверяем логин в phpldapadmin с новым паролем..

Dump and Restore

Recommendations:

slapcat > dump.ldif
slapadd -l dump.ldif

also:

slapcat -n 0 -l config.ldif

phpldapadmin

Ставим штатно по мануалу:

dnf install phpldapadmin

В /etc/phpldapadmin/config.php приводим параметры к виду:

$servers->setValue('server','name','VEDA.Wiki LDAP Server');
$servers->setValue('server','host','192.168.7.27');
$servers->setValue('server','base',array('dc=veda,dc=wiki'));
$servers->setValue('login','bind_id','cn=Manager,dc=veda,dc=wiki');
$config->custom->appearance['hide_template_warning'] = true;

Для nginx создаем конфиг субдомена /etc/nginx/sites-available/vedapla.conf:

server {
    server_name  vedapla.sphynkx.org.ua;
    listen 9597;
    access_log   /var/log/nginx/vedapla-access.log;
    error_log   /var/log/nginx/vedapla-error.log;
    root         /usr/share/phpldapadmin/htdocs;
    index index.php index.html index.htm;
    location / {
    }
    location ~ \.php$ {
        include /etc/nginx/fastcgi_params;
## https://ruhighload.com/%D0%9E%D1%88%D0%B8%D0%B1%D0%BA%D0%B0+nginx+upstream+sent+too+big+header
## was 502 error during saving of big wikipage
        fastcgi_buffer_size 32k;
        fastcgi_buffers 4 32k;
        fastcgi_pass unix:/run/php-fpm/www.sock;
        fastcgi_index index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        try_files $uri @rewrite;
        fastcgi_read_timeout 600;
    }
}

Рестартим nginx, получаем сертификат для домена через letsencrypt (выбираем опцию 2) и опять рестартим nginx:

service nginx restart
letsencrypt
service nginx restart

Теперь сервис будет доступен по адресу https://vedapla.sphynkx.org.ua/. Однако выяснилось, что phpldapadmin не совместим с PHP8 и поддержка появится еще не скоро (хотя уже есть тестовый Docker-образ). С счастью, также имеются патчи, позволяющие временно организовать совместимость текущих версий: 1.2.6.3 и 1.2.6.7. Для версии 1.2.6.6 подошел патч от 1.2.6.7, но накладывать патч пришлось руками. Там в основном перед классами добавляется закомментаренная строка #[\AllowDynamicProperties] и в lib/TemplateRender.php 2 переменные private $url_base; и private $layout;. После этого веб-интерфейс заработал без ошибок.

Авторизация происходит с логином cn=Manager,dc=veda,dc=wiki и паролем, указанном при создании хеша выше.

Интерфейс phpldapadmin выдавал ошибку Unrecognized error number: 8192: Creation of dynamic property TemplateRender::$url_base is deprecatedи не показывал верхнюю панельку с командами/шаблонами.. В lib/TemplateRender.php:15 (перед class TemplateRender extends PageRender) добавлена строка #[\AllowDynamicProperties] и ошибка исчезла, панелька появилась.


SSP

See manuals..

cd /var/www
git clone https://github.com/ltb-project/self-service-password.git
mv self-service-password ssp
cd ssp
composer update
dnf install php-Smarty
ln -s /usr/share/php/Smarty /usr/share/php/smarty3
chown -R apache:apache /var/www/ssp
curl -vv http://localhost:9598/index.php

Next create /etc/nginx/sites-available/ssp.conf:

server {
    server_name  ssp.sphynkx.org.ua;
    listen 9598;
    access_log   /var/log/nginx/ssp-access.log;
    error_log   /var/log/nginx/ssp-error.log;
    root         /var/www/ssp/htdocs;
    index index.php index.html index.htm;
    location / {
    }
    location ~ \.php$ {
        include /etc/nginx/fastcgi_params;
## https://ruhighload.com/%D0%9E%D1%88%D0%B8%D0%B1%D0%BA%D0%B0+nginx+upstream+sent+too+big+header
## was 502 error during saving of big wikipage
        fastcgi_buffer_size 32k;
        fastcgi_buffers 4 32k;
##      fastcgi_pass  127.0.0.1:9000;
        fastcgi_pass unix:/run/php-fpm/www.sock;
        fastcgi_index index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        try_files $uri @rewrite;
        fastcgi_read_timeout 600;
    }
}

and restart nginx.. Also configure /var/www/ssp/conf/config.inc.php - set binddn, password, site url. On hosting server create /etc/nginx/conf.d/ssp.conf:

    server {
        server_name  ssp.sphynkx.org.ua;
        listen       80;
<------>access_log   /var/log/nginx/ssp-access.log  main;
<------>error_log   /var/log/nginx/ssp-error.log;
        location / {
<------>proxy_pass      http://192.168.7.27:9598;
<------>proxy_connect_timeout       600;
<------>proxy_send_timeout          600;
<------>proxy_read_timeout          600;
<------>send_timeout                600;........
<------>}

}

Restart nginx, run letsencrypt (choose option 2), restart nginx.


Переключение скина при авторизации

Неавторизованные юзеры используют скин Tweeki, а авторизованным редакторам нужен Modern. Средства для втоматич.настройки не нашлось, поэтому использован несколько доработанный экстеншн Extension:SkinPerNamespace. Модификации в SkinPerNamespaceHooks.php:

34c34,40
<                       $wgSkinPerNamespaceOverrideLoggedIn;
---
>                       $wgSkinPerNamespaceOverrideLoggedIn, $wgSkinForLoggedIn;
>
>               if ( $context->getUser()->isRegistered() ) {
>                       $skin = $wgSkinForLoggedIn;
>                       return true;
>               }
>

Введена переменная $wgSkinForLoggedIn, хранящая скин для авторизованных юзеров. Настройки в LocalSettings.php:

wfLoadExtension( 'SkinPerNamespace' );
$wgSkinPerNamespace[] = 'tweeki';
$wgSkinForLoggedIn = "modern";

Работает даже слишком хорошо - не позволяет юзерам сменить скин в настройках. Надо бы как-то решить.. Пока введен небольшой хак для юзера SkinProbe (в первых строках фции):

if ( $context->getUser()->getName() === 'SkinProbe' ) {
return true;
}

Баги и ошибки

Баг на слове Трилитон

При охвате кв.скобками слова Трилитон, в случае если после слова шла буква "ы" - почему-то ломался рендеринг и отображалась пустая страница. Решилось охватом буквы "ы" в тег nowiki. Такая же история обнаружилась со словами Лингам, Анх, Джед, Эквадор.

В версии 1.39.3 баг уже не наблюдается.

DPL install issue

При установке новой вики в вики-ферме, при первом обращении к странице использующей DPL вика может рухнуть. Это происходит из-за того что вика закрыта, а при первом обращении DPL пытается создать Template:Extension_DPL от имени анонимного юзера, что запрещено. И экстеншн падает. Надо временно отключить DPL в LocalSettings.php а также временно отключить закрытость вики. Затем включить DPL и зайти на страничку, на которой срабатывает DPL. При этом все нужные шаблоны создадутся. После этого опять закрыть вику.


DPL migration issue

При переезде вики с 1.29 на 1.39 некоторые страницы под управлением DPL (deprecated from 1.34) оказались неработоспособны. В частности Созданные_категории генерировали список категорий, но ссылались на одноименные страницы основного неймспейса, также обнаружилось, что перестали работать переменные %TITLE% и пр. В то же время Заглавная страница генерилась нормально.

При переключении на актуальный DPL Созданные_категории отрабатывалась нормально, но Заглавная страница поломалась - в список попадали страницы картинок, не срабатывал параметр колонок, исчезла раскраска ссылок на перенаправления. Переписать код по другому не удалось.

Получилось подключить обе версии DPL - в коде старой изменен управляющий тег с DPL на DPL2:

--- DPLSetup.php_ISX    2023-07-30 16:47:59.959274489 +0300
+++ DPLSetup.php        2023-07-30 16:49:22.638274489 +0300
@@ -1290,9 +1290,9 @@
                // DPL offers the same functionality as Intersection; so we register the <DynamicPageList> tag
                // in case LabeledSection extension is not installed we need to remove section markers

-               $parser->setHook( 'section', array( __CLASS__, 'removeSectionMarkers' ) );
-               $parser->setHook( 'DPL', array( __CLASS__, 'dplTag' ) );
-               $parser->setHook( 'DynamicPageList', array( __CLASS__, 'intersectionTag' ) );
+               $parser->setHook( 'section2', array( __CLASS__, 'removeSectionMarkers' ) );
+               $parser->setHook( 'DPL2', array( __CLASS__, 'dplTag' ) );
+               $parser->setHook( 'DynamicPageList2', array( __CLASS__, 'intersectionTag' ) );

                $parser->setFunctionHook( 'dpl', array( __CLASS__, 'dplParserFunction' ) );
                $parser->setFunctionHook( 'dplnum', array( __CLASS__, 'dplNumParserFunction' ) );

Также в Заглавной странице тег переключен на DPL2.

Вышеописанное стало неактуальным после переезда на ерсию движка 1.40 - старый экстеншн DPL совсем умер. Пришлось все-таки переделать на новом DPL. Подробности - #Список всех вики-страниц. Также перестали работать генераторы списков для шаблонов, созданных категорий etc. Вместо DPL реализации применен вызов типа:

{{Special:AllPages/Template:|hideredirects=true}}

Для маленьких списков этого достаточно.

Tip'n'Tricks

Отключение запрета на копирование в Telegram-группах

Когда в настройках группы включают защиту контента, пропадает возможность выделить мышкой и скопировать текст. Можно частично отключить эту фичу (она реализована на CSS). Открываем телеграм-группу в Хроме, включаем Веб-девелопер тулз. В заголовках есть подключение CSS-файла, типа index-3IrLF-DD.css (имя наверное динамически генерится). В теге head перед <style>...</style> Открываем его средствами девелопера же (Reveal in Sourses panel). В нем на строке примерно 21819 есть блок:

body {
    background-color: var(--body-background-color);
    color: var(--primary-text-color);
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none
}

"Портим" его - искажаем имена параметров со словом select. В результате восстанавливается возможность выделения мышкой. Меню правой мышки по прежнему перебивается телеграмовым встроенным, поэтому чтоб скопировать - жмем Ctrl+C Но это не все select.. Проще сделать поиск и замену и испортить все вхождения select:. Для восстановления штатного меню правой мышки - тоже самое с вхождением pointer-events. Однако почему-то подряд эти манипуляции не срабатывают - вторая отменяет эффект первой, хотя измененность параметров остается. Значит меняем только select:. Чтобы восстановилась возможность сохранять картинки - портим no-forwards.

Перестали отображаться номера строк и не получилось их включить. В сурс-панели внизу отображается Line 1; Column 425376 - это тоже адрес нужного места, но в исходном однострочном виде. Надо находясь в сурс-панели нажать Ctrl+R - все перегрузится и отобразатся номера строк для уже перерендеренного CSS.


Показ системных сообщений

Добавив к УРЛу ?uselang=qqx можно отобразить мессаджи и названия элементов интерфейса. Появляющиеся названия можно дополнить УРЛом сайта и неймспейсом MediaWiki: напр. (для Special:UserLogin?uselang=qqx):

https://lahwiki.sphynkx.org.ua/MediaWiki:userlogin-yourname (хранит Оставаться в системе ).

Страница логина

В медиавике концептуально нельзя запретить какую-либо страницу для какого-то юзера. Можно настроить права для группы (но не похоже что оно правильно работает). Есть доп. экстеншны для управления доступом..

Страницу логина, похоже, перенести/переименовать нельзя..

Страницу логина можно (Special:Login Special:UserLogin) отредактровать. MediaWiki:Loginprompt - Содержимое этой страницы становится сообщением, которое отображается над экраном входа в систему по адресу Special:UserLogin

MediaWiki:Loginreqpagetext - текст Вы должны $1, чтобы просмотреть другие страницы. где $1 означает ссылку на страницу логина, для которой подставляется текст, настраиваемый в MediaWiki:Loginreqlink (в рус. по дефолту - войти)

На странице MediaWiki:Userlogin-remembermypassword хранится текст Оставаться в системе


Ссылки в футтере

https://stackoverflow.com/questions/54338257/how-to-create-a-new-function-in-mediawiki-not-an-extension

По дефолту страницы содержат тексты:

MediaWiki:Privacy - Политика конфиденциальности, а
MediaWiki:Disclaimers - Отказ от ответственности
MediaWiki:About - Описание
MediaWiki:Description - ссылка с назв. О LAH Wiki ведет на несозданную страницу.

Подключение экстеншнов в цикле

https://ru.wikipedia.org/wiki/Категория:Модули:Викиданные