Wiki source code of FAQ Pages
Last modified by Eleni Cojocariu on 2026/10/09 19:21
Show last authors
| author | version | line-number | content |
|---|---|---|---|
| 1 | One row per [[FAQ>>doc:FAQ.WebHome]], with what it was converted into. The numbers on [[Migration progress>>XWikiOrg.documentation-scripts-queries.migration-progress.WebHome]] are these same queries counted instead of listed. | ||
| 2 | |||
| 3 | {{velocity}} | ||
| 4 | #set ($Q = '"') | ||
| 5 | #set ($mappingClass = 'XWikiOrg.documentation-scripts-queries.MigratedPageClass') | ||
| 6 | #set ($redirectClass = 'XWiki.RedirectClass') | ||
| 7 | ## A FAQ is a page carrying a FAQCode.FAQClass object -- the same set the FAQ home page lists, and | ||
| 8 | ## the same number its live table reports. The FAQ space holds further pages without that object; | ||
| 9 | ## they are deliberately out of scope here. | ||
| 10 | #set ($base = "type:DOCUMENT AND wiki:xwiki AND hidden:false AND space_prefix:${Q}FAQ${Q} AND class:${Q}FAQCode.FAQClass${Q} AND -name:WebPreferences AND doclocale:${Q}${Q}") | ||
| 11 | ## Only the fields the table reads. The first five are mandatory whatever it shows: SolrQueryExecutor | ||
| 12 | ## resolves every result to a DocumentReference to check view rights, and a result it cannot resolve | ||
| 13 | ## is dropped -- an incomplete 'fl' empties the table while the total still looks right. 'class' is | ||
| 14 | ## the multi-valued field holding every class the page carries an object of, and it is what tells an | ||
| 15 | ## entry from a plain page as well as which rows are worth a getDocument() call. | ||
| 16 | #set ($fields = 'wiki,spaces,name,type,doclocale,fullname,title_,class') | ||
| 17 | |||
| 18 | = Pages carrying a FAQ object = | ||
| 19 | |||
| 20 | #set ($query = $services.query.createQuery($base, 'solr')) | ||
| 21 | #set ($discard = $query.setLimit(2000)) | ||
| 22 | #set ($discard = $query.bindValue('fl', $fields)) | ||
| 23 | #set ($discard = $query.bindValue('sort', 'fullname asc')) | ||
| 24 | #set ($results = $query.execute().get(0).results) | ||
| 25 | ## The same test as the Done column of the summary page, so the two can never disagree. | ||
| 26 | #set ($doneQuery = $services.query.createQuery("${base} AND property.XWiki.TagClass.tags:done", 'solr')) | ||
| 27 | #set ($discard = $doneQuery.setLimit(2000)) | ||
| 28 | #set ($discard = $doneQuery.bindValue('fl', $fields)) | ||
| 29 | #set ($doneRefs = []) | ||
| 30 | #foreach ($row in $doneQuery.execute().get(0).results) | ||
| 31 | #set ($discard = $doneRefs.add($row.get('fullname'))) | ||
| 32 | #end | ||
| 33 | #set ($redirectCount = 0) | ||
| 34 | ## Distinct replacement pages of the whole set: several legacy pages often converge on the same new | ||
| 35 | ## page, so this is a count of labels already seen, not a sum of the rows. | ||
| 36 | #set ($allTargets = []) | ||
| 37 | (% class="table" %) | ||
| 38 | |=Legacy page|=Done|=Converted into|=Redirects to | ||
| 39 | #foreach ($row in $results) | ||
| 40 | #set ($fullName = $row.get('fullname')) | ||
| 41 | #set ($title = "$!row.get('title_')") | ||
| 42 | #if ($title == '') | ||
| 43 | #set ($title = "$!row.get('name')") | ||
| 44 | #end | ||
| 45 | #set ($title = $title.replace('|', '~|')) | ||
| 46 | #set ($classes = $row.get('class')) | ||
| 47 | #set ($newPages = '') | ||
| 48 | #set ($redirect = '') | ||
| 49 | #if ($classes && ($classes.contains($mappingClass) || $classes.contains($redirectClass))) | ||
| 50 | #set ($legacyDoc = $xwiki.getDocument($fullName)) | ||
| 51 | #set ($mapping = $legacyDoc.getObject($mappingClass)) | ||
| 52 | #if ($mapping) | ||
| 53 | #set ($newPages = "$!mapping.getValue('newPages')") | ||
| 54 | #end | ||
| 55 | #set ($redirectObject = $legacyDoc.getObject($redirectClass)) | ||
| 56 | #if ($redirectObject) | ||
| 57 | #set ($redirect = "$!redirectObject.getValue('location')") | ||
| 58 | #end | ||
| 59 | #end | ||
| 60 | #if ($doneRefs.contains($fullName)) | ||
| 61 | #set ($doneCell = '✅') | ||
| 62 | #else | ||
| 63 | #set ($doneCell = '❌') | ||
| 64 | #end | ||
| 65 | #set ($targets = []) | ||
| 66 | #set ($targetLabels = []) | ||
| 67 | #foreach ($line in $newPages.split('[\r\n]+')) | ||
| 68 | ## The field holds one wiki link per line, so that moving a replacement page rewrites it: the | ||
| 69 | ## rename job only follows links, and a bare reference it cannot see goes stale silently. Values | ||
| 70 | ## written before that change are still bare, hence unwrapping rather than parsing a link. | ||
| 71 | #set ($target = $line.trim().replaceAll('^\[\[', '').replaceAll('\]\]$', '')) | ||
| 72 | #set ($target = $target.replaceAll('\|\|.*$', '').replaceAll('^.*>>', '')) | ||
| 73 | #set ($target = $target.replaceAll('^doc:', '').trim()) | ||
| 74 | #if ($target != '') | ||
| 75 | #set ($label = $target.replaceAll('^xwiki:', '').replaceAll('\.WebHome$', '')) | ||
| 76 | #set ($discard = $targetLabels.add($label)) | ||
| 77 | #set ($discard = $targets.add("[[$label>>doc:$target]]")) | ||
| 78 | #if (!$allTargets.contains($label)) | ||
| 79 | #set ($discard = $allTargets.add($label)) | ||
| 80 | #end | ||
| 81 | #end | ||
| 82 | #end | ||
| 83 | ## A redirect names a replacement too, and it is the only one most legacy pages have: list it here | ||
| 84 | ## as well, unless the mapping object already records it. | ||
| 85 | #if ($redirect == '') | ||
| 86 | #set ($redirectCell = '—') | ||
| 87 | #else | ||
| 88 | #set ($redirectCount = $redirectCount + 1) | ||
| 89 | #set ($redirectLabel = $redirect.replaceAll('^xwiki:', '').replaceAll('\.WebHome$', '')) | ||
| 90 | #set ($redirectCell = "[[$redirectLabel>>doc:$redirect]]") | ||
| 91 | #if (!$targetLabels.contains($redirectLabel)) | ||
| 92 | #set ($discard = $targets.add("[[$redirectLabel>>doc:$redirect]] //(redirect)//")) | ||
| 93 | #end | ||
| 94 | #if (!$allTargets.contains($redirectLabel)) | ||
| 95 | #set ($discard = $allTargets.add($redirectLabel)) | ||
| 96 | #end | ||
| 97 | #end | ||
| 98 | #if ($targets.isEmpty()) | ||
| 99 | #set ($targetCell = '—') | ||
| 100 | #else | ||
| 101 | #set ($targetCell = $stringtool.join($targets, '\\')) | ||
| 102 | #end | ||
| 103 | |[[$title>>doc:$fullName]]|$doneCell|$targetCell|$redirectCell | ||
| 104 | #end | ||
| 105 | |=**$results.size() pages**|=**$doneRefs.size() done**|=**$allTargets.size() new pages**|=**$redirectCount redirects** | ||
| 106 | {{/velocity}} | ||
| 107 | |||
| 108 | A page counts as **done** when it carries the ##done## tag. //Converted into// is the ##newPages## field of its [[MigratedPageClass>>XWikiOrg.documentation-scripts-queries.MigratedPageClass]] object, so it stays empty until someone records where the content went. The total under //Converted into// counts the **distinct** replacement pages of the set, so it is smaller than the sum of the rows whenever several pages were merged into one. //Redirects to// is the ##location## of an ##XWiki.RedirectClass## object: such a page already sends its readers elsewhere, whether or not anyone marked it as done. None of the three has been used in this space yet, so the table shows the starting state. |