diff options
| author | Lester Caine <lester@lsces.co.uk> | 2026-05-22 15:44:44 +0100 |
|---|---|---|
| committer | Lester Caine <lester@lsces.co.uk> | 2026-05-22 15:44:44 +0100 |
| commit | 572b562f433532429423a5ccace64838efec93c7 (patch) | |
| tree | 2c7a9dbe8570578a58d5b396a15388243628ffda | |
| parent | 825ce764d0e6bcdcaccad653a346e03a25cd267f (diff) | |
| download | liberty-572b562f433532429423a5ccace64838efec93c7.tar.gz liberty-572b562f433532429423a5ccace64838efec93c7.tar.bz2 liberty-572b562f433532429423a5ccace64838efec93c7.zip | |
Add generic xref group/source admin pages to liberty
LibertyXrefType: add getContentTypeGuids() and getGroupList() static methods.
New admin pages with package filter (session-persisted content_type_guid
dropdown): admin_xref_groups.php manages liberty_xref_type rows;
admin_xref_sources.php manages liberty_xref_source rows. Both support
add and delete (delete guarded by entry/source count). Wired into
menu_liberty_admin.tpl as Xref Groups / Xref Sources links.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| -rw-r--r-- | admin/admin_xref_groups.php | 62 | ||||
| -rw-r--r-- | admin/admin_xref_sources.php | 71 | ||||
| -rw-r--r-- | includes/classes/LibertyXrefType.php | 42 | ||||
| -rw-r--r-- | templates/admin_xref_groups.tpl | 100 | ||||
| -rw-r--r-- | templates/admin_xref_sources.tpl | 120 | ||||
| -rwxr-xr-x | templates/menu_liberty_admin.tpl | 2 |
6 files changed, 397 insertions, 0 deletions
diff --git a/admin/admin_xref_groups.php b/admin/admin_xref_groups.php new file mode 100644 index 0000000..8d4ae58 --- /dev/null +++ b/admin/admin_xref_groups.php @@ -0,0 +1,62 @@ +<?php +/** + * Admin page for managing liberty_xref_type groups across all packages. + * @package liberty + */ + +use Bitweaver\Liberty\LibertyXrefType; +use Bitweaver\KernelTools; + +require_once '../../kernel/includes/setup_inc.php'; + +$gBitSystem->verifyPermission( 'p_admin' ); + +// Persist selected content_type_guid in session +if ( isset( $_REQUEST['content_type_guid'] ) ) { + $_SESSION['liberty_xref_admin_guid'] = $_REQUEST['content_type_guid']; +} +$activeGuid = $_SESSION['liberty_xref_admin_guid'] ?? ''; + +// Add a new group +if ( !empty( $_REQUEST['fAddGroup'] ) ) { + $xrefType = trim( $_REQUEST['xref_type'] ?? '' ); + $guid = trim( $_REQUEST['new_content_type_guid'] ?? $activeGuid ); + $title = trim( $_REQUEST['title'] ?? '' ); + $sortOrder = (int)( $_REQUEST['sort_order'] ?? 0 ); + $roleId = (int)( $_REQUEST['role_id'] ?? 3 ); + if ( $xrefType && $guid && $title ) { + $gBitDb->query( + "INSERT INTO `".BIT_DB_PREFIX."liberty_xref_type` (`xref_type`,`content_type_guid`,`title`,`sort_order`,`role_id`,`type_href`) VALUES (?,?,?,?,?,'')", + [ $xrefType, $guid, $title, $sortOrder, $roleId ] + ); + } +} + +// Delete a group (only if no sources are attached) +if ( !empty( $_REQUEST['fDeleteGroup'] ) ) { + $xrefType = $_REQUEST['xref_type'] ?? ''; + $guid = $_REQUEST['del_content_type_guid'] ?? ''; + if ( $xrefType && $guid ) { + $count = $gBitDb->getOne( + "SELECT COUNT(*) FROM `".BIT_DB_PREFIX."liberty_xref_source` WHERE `xref_type` = ? AND `content_type_guid` = ?", + [ $xrefType, $guid ] + ); + if ( $count == 0 ) { + $gBitDb->query( + "DELETE FROM `".BIT_DB_PREFIX."liberty_xref_type` WHERE `xref_type` = ? AND `content_type_guid` = ?", + [ $xrefType, $guid ] + ); + } else { + $gBitSmarty->assign( 'deleteError', "Cannot delete '$xrefType' — $count source(s) still attached." ); + } + } +} + +$guidList = LibertyXrefType::getContentTypeGuids(); +$groups = LibertyXrefType::getGroupList( $activeGuid ? [ 'content_type_guid' => $activeGuid ] : [] ); + +$gBitSmarty->assign( 'activeGuid', $activeGuid ); +$gBitSmarty->assign( 'guidList', $guidList ); +$gBitSmarty->assign( 'xref_groups', $groups ); + +$gBitSystem->display( 'bitpackage:liberty/admin_xref_groups.tpl', KernelTools::tra( 'Xref Groups' ), [ 'display_mode' => 'admin' ] ); diff --git a/admin/admin_xref_sources.php b/admin/admin_xref_sources.php new file mode 100644 index 0000000..c86b0d3 --- /dev/null +++ b/admin/admin_xref_sources.php @@ -0,0 +1,71 @@ +<?php +/** + * Admin page for managing liberty_xref_source entries across all packages. + * @package liberty + */ + +use Bitweaver\Liberty\LibertyXrefType; +use Bitweaver\KernelTools; + +require_once '../../kernel/includes/setup_inc.php'; + +$gBitSystem->verifyPermission( 'p_admin' ); + +// Persist selected content_type_guid in session +if ( isset( $_REQUEST['content_type_guid'] ) ) { + $_SESSION['liberty_xref_admin_guid'] = $_REQUEST['content_type_guid']; +} +$activeGuid = $_SESSION['liberty_xref_admin_guid'] ?? ''; + +// Add a new source +if ( !empty( $_REQUEST['fAddSource'] ) ) { + $source = trim( $_REQUEST['source'] ?? '' ); + $guid = trim( $_REQUEST['new_content_type_guid'] ?? $activeGuid ); + $xrefType = trim( $_REQUEST['xref_type'] ?? '' ); + $title = trim( $_REQUEST['cross_ref_title'] ?? '' ); + $template = trim( $_REQUEST['template'] ?? '' ); + $href = trim( $_REQUEST['cross_ref_href'] ?? '' ); + $multi = (int)( $_REQUEST['multi'] ?? 0 ); + $roleId = (int)( $_REQUEST['role_id'] ?? 3 ); + if ( $source && $guid && $xrefType && $title ) { + $gBitDb->query( + "INSERT INTO `".BIT_DB_PREFIX."liberty_xref_source` (`source`,`content_type_guid`,`xref_type`,`cross_ref_title`,`multi`,`role_id`,`cross_ref_href`,`template`,`data`) VALUES (?,?,?,?,?,?,?,?,NULL)", + [ $source, $guid, $xrefType, $title, $multi, $roleId, $href, $template ] + ); + } +} + +// Delete a source (only if no xref records use it) +if ( !empty( $_REQUEST['fDeleteSource'] ) ) { + $source = $_REQUEST['source'] ?? ''; + $guid = $_REQUEST['del_content_type_guid'] ?? ''; + if ( $source && $guid ) { + $count = $gBitDb->getOne( + "SELECT COUNT(*) FROM `".BIT_DB_PREFIX."liberty_xref` WHERE `source` = ?", + [ $source ] + ); + if ( $count == 0 ) { + $gBitDb->query( + "DELETE FROM `".BIT_DB_PREFIX."liberty_xref_source` WHERE `source` = ? AND `content_type_guid` = ?", + [ $source, $guid ] + ); + } else { + $gBitSmarty->assign( 'deleteError', "Cannot delete '$source' — $count xref record(s) still use it." ); + } + } +} + +$guidList = LibertyXrefType::getContentTypeGuids(); +$sources = LibertyXrefType::getXrefTypeList( $activeGuid ? [ 'content_type_guid' => $activeGuid ] : [] ); + +// Build group list for the add-form dropdown, filtered to active guid +$groups = $activeGuid + ? LibertyXrefType::getGroupList( [ 'content_type_guid' => $activeGuid ] ) + : []; + +$gBitSmarty->assign( 'activeGuid', $activeGuid ); +$gBitSmarty->assign( 'guidList', $guidList ); +$gBitSmarty->assign( 'xref_sources', $sources ); +$gBitSmarty->assign( 'xref_groups', $groups ); + +$gBitSystem->display( 'bitpackage:liberty/admin_xref_sources.tpl', KernelTools::tra( 'Xref Sources' ), [ 'display_mode' => 'admin' ] ); diff --git a/includes/classes/LibertyXrefType.php b/includes/classes/LibertyXrefType.php index 321db07..00f2cb2 100644 --- a/includes/classes/LibertyXrefType.php +++ b/includes/classes/LibertyXrefType.php @@ -50,4 +50,46 @@ class LibertyXrefType extends LibertyBase { return $ret; } + + /** + * Returns the distinct content_type_guid values present in liberty_xref_type. + */ + public static function getContentTypeGuids(): array { + global $gBitSystem; + $result = $gBitSystem->mDb->query( + "SELECT DISTINCT `content_type_guid` FROM `".BIT_DB_PREFIX."liberty_xref_type` ORDER BY `content_type_guid`", + [] + ); + $ret = []; + while ( $res = $result->fetchRow() ) { + $ret[] = $res['content_type_guid']; + } + return $ret; + } + + /** + * Returns liberty_xref_type rows, optionally filtered by content_type_guid. + * Each row includes num_sources: count of sources defined for that group. + */ + public static function getGroupList( $pOptionHash = NULL ): array { + global $gBitSystem; + $where = ''; + $bindVars = []; + if ( !empty( $pOptionHash['content_type_guid'] ) ) { + $where = " WHERE cxt.`content_type_guid` = ?"; + $bindVars[] = $pOptionHash['content_type_guid']; + } + $query = "SELECT cxt.* FROM `".BIT_DB_PREFIX."liberty_xref_type` cxt + $where ORDER BY cxt.`content_type_guid`, cxt.`sort_order`"; + $result = $gBitSystem->mDb->query( $query, $bindVars ); + $ret = []; + while ( $res = $result->fetchRow() ) { + $res['num_sources'] = $gBitSystem->mDb->getOne( + "SELECT COUNT(*) FROM `".BIT_DB_PREFIX."liberty_xref_source` WHERE `xref_type` = ? AND `content_type_guid` = ?", + [ $res['xref_type'], $res['content_type_guid'] ] + ); + $ret[] = $res; + } + return $ret; + } } diff --git a/templates/admin_xref_groups.tpl b/templates/admin_xref_groups.tpl new file mode 100644 index 0000000..3618c79 --- /dev/null +++ b/templates/admin_xref_groups.tpl @@ -0,0 +1,100 @@ +{* Admin: liberty_xref_type groups *} +{strip} +<div class="floaticon">{bithelp}</div> + +<div class="admin liberty"> + <div class="header"> + <h1>{tr}Xref Groups{/tr}</h1> + </div> + + <div class="body"> + + {* Package filter *} + <form method="get" action="{$smarty.const.LIBERTY_PKG_URL}admin/admin_xref_groups.php" class="form-inline"> + <div class="form-group"> + <label for="content_type_guid">{tr}Package{/tr}</label> + <select name="content_type_guid" id="content_type_guid" class="form-control"> + <option value="">{tr}— All packages —{/tr}</option> + {foreach from=$guidList item=guid} + <option value="{$guid|escape}" {if $guid eq $activeGuid}selected="selected"{/if}>{$guid|escape}</option> + {/foreach} + </select> + <button type="submit" class="btn btn-default">{tr}Filter{/tr}</button> + {if $activeGuid} + <a href="{$smarty.const.LIBERTY_PKG_URL}admin/admin_xref_groups.php?content_type_guid=" class="btn btn-link">{tr}Clear{/tr}</a> + {/if} + </div> + </form> + + {if $deleteError} + <div class="alert alert-danger">{$deleteError|escape}</div> + {/if} + + {* Add group form *} + {if $activeGuid} + {form legend="Add Xref Group" action="{$smarty.const.LIBERTY_PKG_URL}admin/admin_xref_groups.php"} + <input type="hidden" name="new_content_type_guid" value="{$activeGuid|escape}" /> + <input type="hidden" name="content_type_guid" value="{$activeGuid|escape}" /> + <div class="form-group"> + {formlabel label="Key (xref_type)" for="xref_type"} + {forminput}<input type="text" id="xref_type" name="xref_type" class="form-control" />{/forminput} + </div> + <div class="form-group"> + {formlabel label="Title" for="title"} + {forminput}<input type="text" id="title" name="title" class="form-control" />{/forminput} + </div> + <div class="form-group"> + {formlabel label="Sort Order" for="sort_order"} + {forminput}<input type="number" id="sort_order" name="sort_order" value="1" class="form-control" style="width:5em" />{/forminput} + </div> + <div class="form-group"> + {formlabel label="Role ID" for="role_id"} + {forminput}<input type="number" id="role_id" name="role_id" value="3" class="form-control" style="width:5em" />{/forminput} + </div> + <div class="form-group submit"> + <input type="submit" class="btn btn-primary" name="fAddGroup" value="{tr}Add Group{/tr}" /> + </div> + {/form} + {/if} + + {* Group list *} + <table class="table table-striped data"> + <caption>{tr}Xref Groups{/tr} {if $activeGuid}— {$activeGuid|escape}{/if}</caption> + <thead> + <tr> + <th>{tr}Package{/tr}</th> + <th>{tr}Key{/tr}</th> + <th>{tr}Title{/tr}</th> + <th>{tr}Sort{/tr}</th> + <th>{tr}Role{/tr}</th> + <th>{tr}Sources{/tr}</th> + <th>{tr}Actions{/tr}</th> + </tr> + </thead> + <tbody> + {foreach from=$xref_groups item=grp} + <tr> + <td>{$grp.content_type_guid|escape}</td> + <td><code>{$grp.xref_type|escape}</code></td> + <td>{$grp.title|escape}</td> + <td>{$grp.sort_order}</td> + <td>{$grp.role_id}</td> + <td> + <a href="{$smarty.const.LIBERTY_PKG_URL}admin/admin_xref_sources.php?content_type_guid={$grp.content_type_guid|escape}">{$grp.num_sources}</a> + </td> + <td> + {if $grp.num_sources eq 0} + <a href="{$smarty.const.LIBERTY_PKG_URL}admin/admin_xref_groups.php?fDeleteGroup=1&xref_type={$grp.xref_type|escape}&del_content_type_guid={$grp.content_type_guid|escape}&content_type_guid={$activeGuid|escape}" + onclick="return confirm('{tr}Delete this group?{/tr}')">{booticon iname="icon-trash" ipackage="icons" iforce=icon_text iexplain="Delete"}</a> + {/if} + </td> + </tr> + {foreachelse} + <tr class="norecords"><td colspan="7">{tr}No groups found{/tr}</td></tr> + {/foreach} + </tbody> + </table> + + </div><!-- end .body --> +</div><!-- end .admin --> +{/strip} diff --git a/templates/admin_xref_sources.tpl b/templates/admin_xref_sources.tpl new file mode 100644 index 0000000..58fddf6 --- /dev/null +++ b/templates/admin_xref_sources.tpl @@ -0,0 +1,120 @@ +{* Admin: liberty_xref_source entries *} +{strip} +<div class="floaticon">{bithelp}</div> + +<div class="admin liberty"> + <div class="header"> + <h1>{tr}Xref Sources{/tr}</h1> + </div> + + <div class="body"> + + {* Package filter *} + <form method="get" action="{$smarty.const.LIBERTY_PKG_URL}admin/admin_xref_sources.php" class="form-inline"> + <div class="form-group"> + <label for="content_type_guid">{tr}Package{/tr}</label> + <select name="content_type_guid" id="content_type_guid" class="form-control"> + <option value="">{tr}— All packages —{/tr}</option> + {foreach from=$guidList item=guid} + <option value="{$guid|escape}" {if $guid eq $activeGuid}selected="selected"{/if}>{$guid|escape}</option> + {/foreach} + </select> + <button type="submit" class="btn btn-default">{tr}Filter{/tr}</button> + {if $activeGuid} + <a href="{$smarty.const.LIBERTY_PKG_URL}admin/admin_xref_sources.php?content_type_guid=" class="btn btn-link">{tr}Clear{/tr}</a> + {/if} + </div> + </form> + + {if $deleteError} + <div class="alert alert-danger">{$deleteError|escape}</div> + {/if} + + {* Add source form — only when a package is selected (need a group to assign to) *} + {if $activeGuid && $xref_groups} + {form legend="Add Xref Source" action="{$smarty.const.LIBERTY_PKG_URL}admin/admin_xref_sources.php"} + <input type="hidden" name="new_content_type_guid" value="{$activeGuid|escape}" /> + <input type="hidden" name="content_type_guid" value="{$activeGuid|escape}" /> + <div class="form-group"> + {formlabel label="Source key" for="source"} + {forminput}<input type="text" id="source" name="source" class="form-control" />{/forminput} + </div> + <div class="form-group"> + {formlabel label="Group" for="xref_type"} + {forminput} + <select name="xref_type" id="xref_type" class="form-control"> + {foreach from=$xref_groups item=grp} + <option value="{$grp.xref_type|escape}">{$grp.title|escape} ({$grp.xref_type|escape})</option> + {/foreach} + </select> + {/forminput} + </div> + <div class="form-group"> + {formlabel label="Title" for="cross_ref_title"} + {forminput}<input type="text" id="cross_ref_title" name="cross_ref_title" class="form-control" />{/forminput} + </div> + <div class="form-group"> + {formlabel label="Template" for="template"} + {forminput}<input type="text" id="template" name="template" placeholder="text / address / phone …" class="form-control" />{/forminput} + </div> + <div class="form-group"> + {formlabel label="Href" for="cross_ref_href"} + {forminput}<input type="text" id="cross_ref_href" name="cross_ref_href" class="form-control" />{/forminput} + </div> + <div class="form-group"> + {formlabel label="Multi" for="multi"} + {forminput}<input type="number" id="multi" name="multi" value="0" class="form-control" style="width:5em" />{/forminput} + </div> + <div class="form-group"> + {formlabel label="Role ID" for="role_id"} + {forminput}<input type="number" id="role_id" name="role_id" value="3" class="form-control" style="width:5em" />{/forminput} + </div> + <div class="form-group submit"> + <input type="submit" class="btn btn-primary" name="fAddSource" value="{tr}Add Source{/tr}" /> + </div> + {/form} + {/if} + + {* Source list *} + <table class="table table-striped data"> + <caption>{tr}Xref Sources{/tr} {if $activeGuid}— {$activeGuid|escape}{/if}</caption> + <thead> + <tr> + <th>{tr}Package{/tr}</th> + <th>{tr}Source{/tr}</th> + <th>{tr}Group{/tr}</th> + <th>{tr}Title{/tr}</th> + <th>{tr}Template{/tr}</th> + <th>{tr}Multi{/tr}</th> + <th>{tr}Role{/tr}</th> + <th>{tr}Entries{/tr}</th> + <th>{tr}Actions{/tr}</th> + </tr> + </thead> + <tbody> + {foreach from=$xref_sources item=src} + <tr> + <td>{$src.content_type_guid|escape}</td> + <td><code>{$src.source|escape}</code></td> + <td><code>{$src.xref_type|escape}</code></td> + <td>{$src.cross_ref_title|escape}</td> + <td>{$src.template|escape}</td> + <td>{$src.multi}</td> + <td>{$src.role_id}</td> + <td>{$src.num_entries}</td> + <td> + {if $src.num_entries eq 0} + <a href="{$smarty.const.LIBERTY_PKG_URL}admin/admin_xref_sources.php?fDeleteSource=1&source={$src.source|escape}&del_content_type_guid={$src.content_type_guid|escape}&content_type_guid={$activeGuid|escape}" + onclick="return confirm('{tr}Delete this source?{/tr}')">{booticon iname="icon-trash" ipackage="icons" iforce=icon_text iexplain="Delete"}</a> + {/if} + </td> + </tr> + {foreachelse} + <tr class="norecords"><td colspan="9">{tr}No sources found{/tr}</td></tr> + {/foreach} + </tbody> + </table> + + </div><!-- end .body --> +</div><!-- end .admin --> +{/strip} diff --git a/templates/menu_liberty_admin.tpl b/templates/menu_liberty_admin.tpl index 57a29dd..8dd5e64 100755 --- a/templates/menu_liberty_admin.tpl +++ b/templates/menu_liberty_admin.tpl @@ -5,6 +5,8 @@ <li><a class="item" href="{$smarty.const.LIBERTY_PKG_URL}admin/plugins.php">{tr}Plugins{/tr}</a></li> <li><a class="item" href="{$smarty.const.LIBERTY_PKG_URL}admin/action_logs.php">{tr}Action Logs{/tr}</a></li> <li><a class="item" href="{$smarty.const.LIBERTY_PKG_URL}admin/comments.php">{tr}Comments{/tr}</a></li> + <li><a class="item" href="{$smarty.const.LIBERTY_PKG_URL}admin/admin_xref_groups.php">{tr}Xref Groups{/tr}</a></li> + <li><a class="item" href="{$smarty.const.LIBERTY_PKG_URL}admin/admin_xref_sources.php">{tr}Xref Sources{/tr}</a></li> {if $gBitSystem->isPackageActive( 'pdf' ) } <li><a class="item" href="{$smarty.const.KERNEL_PKG_URL}admin/index.php?page=pdf">{tr}PDF{/tr}</a></li> {/if} |
