--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/5.4/acpMenu.xsd">
+ <import>
+ <acpmenuitem name="wcf.acp.menu.link.person">
+ <parent>wcf.acp.menu.link.content</parent>
+ </acpmenuitem>
+ <acpmenuitem name="wcf.acp.menu.link.person.list">
+ <controller>wcf\acp\page\PersonListPage</controller>
+ <parent>wcf.acp.menu.link.person</parent>
+ <permissions>admin.content.canManagePeople</permissions>
+ </acpmenuitem>
+ <acpmenuitem name="wcf.acp.menu.link.person.add">
+ <controller>wcf\acp\form\PersonAddForm</controller>
+ <parent>wcf.acp.menu.link.person.list</parent>
+ <permissions>admin.content.canManagePeople</permissions>
+ <icon>fa-plus</icon>
+ </acpmenuitem>
+ </import>
+</data>
--- /dev/null
+{include file='header' pageTitle='wcf.acp.person.'|concat:$action}
+
+<header class="contentHeader">
+ <div class="contentHeaderTitle">
+ <h1 class="contentTitle">{lang}wcf.acp.person.{$action}{/lang}</h1>
+ </div>
+
+ <nav class="contentHeaderNavigation">
+ <ul>
+ <li><a href="{link controller='PersonList'}{/link}" class="button"><span class="icon icon16 fa-list"></span> <span>{lang}wcf.acp.menu.link.person.list{/lang}</span></a></li>
+
+ {event name='contentHeaderNavigation'}
+ </ul>
+ </nav>
+</header>
+
+{@$form->getHtml()}
+
+{include file='footer'}
--- /dev/null
+{include file='header' pageTitle='wcf.acp.person.list'}
+
+<header class="contentHeader">
+ <div class="contentHeaderTitle">
+ <h1 class="contentTitle">{lang}wcf.acp.person.list{/lang}</h1>
+ </div>
+
+ <nav class="contentHeaderNavigation">
+ <ul>
+ <li><a href="{link controller='PersonAdd'}{/link}" class="button"><span class="icon icon16 fa-plus"></span> <span>{lang}wcf.acp.menu.link.person.add{/lang}</span></a></li>
+
+ {event name='contentHeaderNavigation'}
+ </ul>
+ </nav>
+</header>
+
+{hascontent}
+ <div class="paginationTop">
+ {content}{pages print=true assign=pagesLinks controller="PersonList" link="pageNo=%d&sortField=$sortField&sortOrder=$sortOrder"}{/content}
+ </div>
+{/hascontent}
+
+{if $objects|count}
+ <div class="section tabularBox">
+ <table class="table jsObjectActionContainer" data-object-action-class-name="wcf\data\person\PersonAction">
+ <thead>
+ <tr>
+ <th class="columnID columnPersonID{if $sortField == 'personID'} active {@$sortOrder}{/if}" colspan="2"><a href="{link controller='PersonList'}pageNo={@$pageNo}&sortField=personID&sortOrder={if $sortField == 'personID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.global.objectID{/lang}</a></th>
+ <th class="columnTitle columnFirstName{if $sortField == 'firstName'} active {@$sortOrder}{/if}"><a href="{link controller='PersonList'}pageNo={@$pageNo}&sortField=firstName&sortOrder={if $sortField == 'firstName' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.person.firstName{/lang}</a></th>
+ <th class="columnTitle columnLastName{if $sortField == 'lastName'} active {@$sortOrder}{/if}"><a href="{link controller='PersonList'}pageNo={@$pageNo}&sortField=lastName&sortOrder={if $sortField == 'lastName' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.person.lastName{/lang}</a></th>
+
+ {event name='columnHeads'}
+ </tr>
+ </thead>
+
+ <tbody class="jsReloadPageWhenEmpty">
+ {foreach from=$objects item=person}
+ <tr class="jsObjectActionObject" data-object-id="{@$person->getObjectID()}">
+ <td class="columnIcon">
+ <a href="{link controller='PersonEdit' object=$person}{/link}" title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip"><span class="icon icon16 fa-pencil"></span></a>
+ {objectAction action="delete" objectTitle=$person->getTitle()}
+
+ {event name='rowButtons'}
+ </td>
+ <td class="columnID">{#$person->personID}</td>
+ <td class="columnTitle columnFirstName"><a href="{link controller='PersonEdit' object=$person}{/link}">{$person->firstName}</a></td>
+ <td class="columnTitle columnLastName"><a href="{link controller='PersonEdit' object=$person}{/link}">{$person->lastName}</a></td>
+
+ {event name='columns'}
+ </tr>
+ {/foreach}
+ </tbody>
+ </table>
+ </div>
+
+ <footer class="contentFooter">
+ {hascontent}
+ <div class="paginationBottom">
+ {content}{@$pagesLinks}{/content}
+ </div>
+ {/hascontent}
+
+ <nav class="contentFooterNavigation">
+ <ul>
+ <li><a href="{link controller='PersonAdd'}{/link}" class="button"><span class="icon icon16 fa-plus"></span> <span>{lang}wcf.acp.menu.link.person.add{/lang}</span></a></li>
+
+ {event name='contentFooterNavigation'}
+ </ul>
+ </nav>
+ </footer>
+{else}
+ <p class="info">{lang}wcf.global.noItems{/lang}</p>
+{/if}
+
+{include file='footer'}
--- /dev/null
+<?php
+
+use wcf\system\database\table\column\DefaultTrueBooleanDatabaseTableColumn;
+use wcf\system\database\table\column\NotNullVarchar255DatabaseTableColumn;
+use wcf\system\database\table\column\ObjectIdDatabaseTableColumn;
+use wcf\system\database\table\column\SmallintDatabaseTableColumn;
+use wcf\system\database\table\DatabaseTable;
+
+return [
+ DatabaseTable::create('wcf1_person')
+ ->columns([
+ ObjectIdDatabaseTableColumn::create('personID'),
+ NotNullVarchar255DatabaseTableColumn::create('firstName'),
+ NotNullVarchar255DatabaseTableColumn::create('lastName'),
+ SmallintDatabaseTableColumn::create('comments')
+ ->length(5)
+ ->notNull()
+ ->defaultValue(0),
+ DefaultTrueBooleanDatabaseTableColumn::create('enableComments'),
+ ]),
+];
--- /dev/null
+<?php
+
+namespace wcf\acp\form;
+
+use wcf\data\person\PersonAction;
+use wcf\form\AbstractFormBuilderForm;
+use wcf\system\form\builder\container\FormContainer;
+use wcf\system\form\builder\field\BooleanFormField;
+use wcf\system\form\builder\field\TextFormField;
+
+/**
+ * Shows the form to create a new person.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Acp\Form
+ */
+class PersonAddForm extends AbstractFormBuilderForm
+{
+ /**
+ * @inheritDoc
+ */
+ public $activeMenuItem = 'wcf.acp.menu.link.person.add';
+
+ /**
+ * @inheritDoc
+ */
+ public $formAction = 'create';
+
+ /**
+ * @inheritDoc
+ */
+ public $neededPermissions = ['admin.content.canManagePeople'];
+
+ /**
+ * @inheritDoc
+ */
+ public $objectActionClass = PersonAction::class;
+
+ /**
+ * @inheritDoc
+ */
+ public $objectEditLinkController = PersonEditForm::class;
+
+ /**
+ * @inheritDoc
+ */
+ public function createForm()
+ {
+ parent::createForm();
+
+ $this->form->appendChild(
+ FormContainer::create('data')
+ ->label('wcf.global.form.data')
+ ->appendChildren([
+ TextFormField::create('firstName')
+ ->label('wcf.person.firstName')
+ ->required()
+ ->autoFocus()
+ ->maximumLength(255),
+
+ TextFormField::create('lastName')
+ ->label('wcf.person.lastName')
+ ->required()
+ ->maximumLength(255),
+
+ BooleanFormField::create('enableComments')
+ ->label('wcf.person.enableComments')
+ ->description('wcf.person.enableComments.description')
+ ->value(true),
+ ])
+ );
+ }
+}
--- /dev/null
+<?php
+
+namespace wcf\acp\form;
+
+use wcf\data\person\Person;
+use wcf\system\exception\IllegalLinkException;
+
+/**
+ * Shows the form to edit an existing person.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Acp\Form
+ */
+class PersonEditForm extends PersonAddForm
+{
+ /**
+ * @inheritDoc
+ */
+ public $activeMenuItem = 'wcf.acp.menu.link.person';
+
+ /**
+ * @inheritDoc
+ */
+ public $formAction = 'update';
+
+ /**
+ * @inheritDoc
+ */
+ public function readParameters()
+ {
+ parent::readParameters();
+
+ if (isset($_REQUEST['id'])) {
+ $this->formObject = new Person($_REQUEST['id']);
+
+ if (!$this->formObject->getObjectID()) {
+ throw new IllegalLinkException();
+ }
+ }
+ }
+}
--- /dev/null
+<?php
+
+namespace wcf\acp\page;
+
+use wcf\data\person\PersonList;
+use wcf\page\SortablePage;
+
+/**
+ * Shows the list of people.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Acp\Page
+ */
+class PersonListPage extends SortablePage
+{
+ /**
+ * @inheritDoc
+ */
+ public $activeMenuItem = 'wcf.acp.menu.link.person.list';
+
+ /**
+ * @inheritDoc
+ */
+ public $neededPermissions = ['admin.content.canManagePeople'];
+
+ /**
+ * @inheritDoc
+ */
+ public $objectListClassName = PersonList::class;
+
+ /**
+ * @inheritDoc
+ */
+ public $validSortFields = ['personID', 'firstName', 'lastName'];
+}
--- /dev/null
+<?php
+
+namespace wcf\data\person;
+
+use wcf\data\DatabaseObject;
+use wcf\data\ITitledLinkObject;
+use wcf\page\PersonPage;
+use wcf\system\request\LinkHandler;
+
+/**
+ * Represents a person.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Data\Person
+ *
+ * @property-read integer $personID unique id of the person
+ * @property-read string $firstName first name of the person
+ * @property-read string $lastName last name of the person
+ * @property-read int $enableComments is `1` if comments are enabled for the person, otherwise `0`
+ */
+class Person extends DatabaseObject implements ITitledLinkObject
+{
+ /**
+ * Returns the first and last name of the person if a person object is treated as a string.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->getTitle();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getLink()
+ {
+ return LinkHandler::getInstance()->getControllerLink(PersonPage::class, [
+ 'object' => $this,
+ ]);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getTitle()
+ {
+ return $this->firstName . ' ' . $this->lastName;
+ }
+}
--- /dev/null
+<?php
+
+namespace wcf\data\person;
+
+use wcf\data\AbstractDatabaseObjectAction;
+
+/**
+ * Executes person-related actions.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Data\Person
+ *
+ * @method Person create()
+ * @method PersonEditor[] getObjects()
+ * @method PersonEditor getSingleObject()
+ */
+class PersonAction extends AbstractDatabaseObjectAction
+{
+ /**
+ * @inheritDoc
+ */
+ protected $permissionsDelete = ['admin.content.canManagePeople'];
+
+ /**
+ * @inheritDoc
+ */
+ protected $requireACP = ['delete'];
+}
--- /dev/null
+<?php
+
+namespace wcf\data\person;
+
+use wcf\data\DatabaseObjectEditor;
+
+/**
+ * Provides functions to edit people.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Data\Person
+ *
+ * @method static Person create(array $parameters = [])
+ * @method Person getDecoratedObject()
+ * @mixin Person
+ */
+class PersonEditor extends DatabaseObjectEditor
+{
+ /**
+ * @inheritDoc
+ */
+ protected static $baseClass = Person::class;
+}
--- /dev/null
+<?php
+
+namespace wcf\data\person;
+
+use wcf\data\DatabaseObjectList;
+
+/**
+ * Represents a list of people.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Data\Person
+ *
+ * @method Person current()
+ * @method Person[] getObjects()
+ * @method Person|null search($objectID)
+ * @property Person[] $objects
+ */
+class PersonList extends DatabaseObjectList
+{
+}
--- /dev/null
+<?php
+
+namespace wcf\page;
+
+use wcf\data\person\PersonList;
+
+/**
+ * Shows the list of people.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Page
+ */
+class PersonListPage extends SortablePage
+{
+ /**
+ * @inheritDoc
+ */
+ public $defaultSortField = 'lastName';
+
+ /**
+ * @inheritDoc
+ */
+ public $objectListClassName = PersonList::class;
+
+ /**
+ * @inheritDoc
+ */
+ public $validSortFields = ['personID', 'firstName', 'lastName'];
+}
--- /dev/null
+<?php
+
+namespace wcf\page;
+
+use wcf\data\person\Person;
+use wcf\system\comment\CommentHandler;
+use wcf\system\comment\manager\PersonCommentManager;
+use wcf\system\exception\IllegalLinkException;
+use wcf\system\WCF;
+
+/**
+ * Shows the details of a certain person.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Page
+ */
+class PersonPage extends AbstractPage
+{
+ /**
+ * list of comments
+ * @var StructuredCommentList
+ */
+ public $commentList;
+
+ /**
+ * person comment manager object
+ * @var PersonCommentManager
+ */
+ public $commentManager;
+
+ /**
+ * id of the person comment object type
+ * @var integer
+ */
+ public $commentObjectTypeID = 0;
+
+ /**
+ * shown person
+ * @var Person
+ */
+ public $person;
+
+ /**
+ * id of the shown person
+ * @var integer
+ */
+ public $personID = 0;
+
+ /**
+ * @inheritDoc
+ */
+ public function assignVariables()
+ {
+ parent::assignVariables();
+
+ WCF::getTPL()->assign([
+ 'commentCanAdd' => WCF::getSession()->getPermission('user.person.canAddComment'),
+ 'commentList' => $this->commentList,
+ 'commentObjectTypeID' => $this->commentObjectTypeID,
+ 'lastCommentTime' => $this->commentList ? $this->commentList->getMinCommentTime() : 0,
+ 'likeData' => MODULE_LIKE && $this->commentList ? $this->commentList->getLikeData() : [],
+ 'person' => $this->person,
+ ]);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function readData()
+ {
+ parent::readData();
+
+ if ($this->person->enableComments) {
+ $this->commentObjectTypeID = CommentHandler::getInstance()->getObjectTypeID(
+ 'com.woltlab.wcf.person.personComment'
+ );
+ $this->commentManager = CommentHandler::getInstance()->getObjectType(
+ $this->commentObjectTypeID
+ )->getProcessor();
+ $this->commentList = CommentHandler::getInstance()->getCommentList(
+ $this->commentManager,
+ $this->commentObjectTypeID,
+ $this->person->personID
+ );
+ }
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function readParameters()
+ {
+ parent::readParameters();
+
+ if (isset($_REQUEST['id'])) {
+ $this->personID = \intval($_REQUEST['id']);
+ }
+ $this->person = new Person($this->personID);
+ if (!$this->person->personID) {
+ throw new IllegalLinkException();
+ }
+ }
+}
--- /dev/null
+<?php
+
+namespace wcf\system\box;
+
+use wcf\data\person\PersonList;
+use wcf\system\WCF;
+
+/**
+ * Dynamic box controller implementation for a list of persons.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\System\Box
+ */
+class PersonListBoxController extends AbstractDatabaseObjectListBoxController
+{
+ /**
+ * @inheritDoc
+ */
+ protected $conditionDefinition = 'com.woltlab.wcf.box.personList.condition';
+
+ /**
+ * @inheritDoc
+ */
+ public $defaultLimit = 5;
+
+ /**
+ * @inheritDoc
+ */
+ protected $sortFieldLanguageItemPrefix = 'wcf.person';
+
+ /**
+ * @inheritDoc
+ */
+ protected static $supportedPositions = [
+ 'sidebarLeft',
+ 'sidebarRight',
+ ];
+
+ /**
+ * @inheritDoc
+ */
+ public $validSortFields = [
+ 'firstName',
+ 'lastName',
+ 'comments',
+ ];
+
+ /**
+ * @inheritDoc
+ */
+ public function getObjectList()
+ {
+ return new PersonList();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function getTemplate()
+ {
+ return WCF::getTPL()->fetch('boxPersonList', 'wcf', [
+ 'boxPersonList' => $this->objectList,
+ 'boxSortField' => $this->sortField,
+ 'boxPosition' => $this->box->position,
+ ], true);
+ }
+}
--- /dev/null
+<?php
+
+namespace wcf\system\cache\runtime;
+
+use wcf\data\person\Person;
+use wcf\data\person\PersonList;
+
+/**
+ * Runtime cache implementation for people.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\System\Cache\Runtime
+ *
+ * @method Person[] getCachedObjects()
+ * @method Person getObject($objectID)
+ * @method Person[] getObjects(array $objectIDs)
+ */
+class PersonRuntimeCache extends AbstractRuntimeCache
+{
+ /**
+ * @inheritDoc
+ */
+ protected $listClassName = PersonList::class;
+}
--- /dev/null
+<?php
+
+namespace wcf\system\comment\manager;
+
+use wcf\data\person\Person;
+use wcf\data\person\PersonEditor;
+use wcf\system\cache\runtime\PersonRuntimeCache;
+use wcf\system\WCF;
+
+/**
+ * Comment manager implementation for people.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\System\Comment\Manager
+ */
+class PersonCommentManager extends AbstractCommentManager
+{
+ /**
+ * @inheritDoc
+ */
+ protected $permissionAdd = 'user.person.canAddComment';
+
+ /**
+ * @inheritDoc
+ */
+ protected $permissionAddWithoutModeration = 'user.person.canAddCommentWithoutModeration';
+
+ /**
+ * @inheritDoc
+ */
+ protected $permissionCanModerate = 'mod.person.canModerateComment';
+
+ /**
+ * @inheritDoc
+ */
+ protected $permissionDelete = 'user.person.canDeleteComment';
+
+ /**
+ * @inheritDoc
+ */
+ protected $permissionEdit = 'user.person.canEditComment';
+
+ /**
+ * @inheritDoc
+ */
+ protected $permissionModDelete = 'mod.person.canDeleteComment';
+
+ /**
+ * @inheritDoc
+ */
+ protected $permissionModEdit = 'mod.person.canEditComment';
+
+ /**
+ * @inheritDoc
+ */
+ public function getLink($objectTypeID, $objectID)
+ {
+ return PersonRuntimeCache::getInstance()->getObject($objectID)->getLink();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function isAccessible($objectID, $validateWritePermission = false)
+ {
+ return PersonRuntimeCache::getInstance()->getObject($objectID) !== null;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getTitle($objectTypeID, $objectID, $isResponse = false)
+ {
+ if ($isResponse) {
+ return WCF::getLanguage()->get('wcf.person.commentResponse');
+ }
+
+ return WCF::getLanguage()->getDynamicVariable('wcf.person.comment');
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function updateCounter($objectID, $value)
+ {
+ (new PersonEditor(new Person($objectID)))->updateCounters(['comments' => $value]);
+ }
+}
--- /dev/null
+<?php
+
+namespace wcf\system\condition\person;
+
+use wcf\data\person\Person;
+use wcf\system\condition\AbstractObjectTextPropertyCondition;
+
+/**
+ * Condition implementation for the first name of a person.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license WoltLab License <http://www.woltlab.com/license-agreement.html>
+ * @package WoltLabSuite\Core\System\Condition
+ */
+class PersonFirstNameTextPropertyCondition extends AbstractObjectTextPropertyCondition
+{
+ /**
+ * @inheritDoc
+ */
+ protected $className = Person::class;
+
+ /**
+ * @inheritDoc
+ */
+ protected $description = 'wcf.person.condition.firstName.description';
+
+ /**
+ * @inheritDoc
+ */
+ protected $fieldName = 'personFirstName';
+
+ /**
+ * @inheritDoc
+ */
+ protected $label = 'wcf.person.firstName';
+
+ /**
+ * @inheritDoc
+ */
+ protected $propertyName = 'firstName';
+
+ /**
+ * @inheritDoc
+ */
+ protected $supportsMultipleValues = true;
+}
--- /dev/null
+<?php
+
+namespace wcf\system\condition\person;
+
+use wcf\data\person\Person;
+use wcf\system\condition\AbstractObjectTextPropertyCondition;
+
+/**
+ * Condition implementation for the last name of a person.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license WoltLab License <http://www.woltlab.com/license-agreement.html>
+ * @package WoltLabSuite\Core\System\Condition
+ */
+class PersonLastNameTextPropertyCondition extends AbstractObjectTextPropertyCondition
+{
+ /**
+ * @inheritDoc
+ */
+ protected $className = Person::class;
+
+ /**
+ * @inheritDoc
+ */
+ protected $description = 'wcf.person.condition.lastName.description';
+
+ /**
+ * @inheritDoc
+ */
+ protected $fieldName = 'personLastName';
+
+ /**
+ * @inheritDoc
+ */
+ protected $label = 'wcf.person.lastName';
+
+ /**
+ * @inheritDoc
+ */
+ protected $propertyName = 'lastName';
+
+ /**
+ * @inheritDoc
+ */
+ protected $supportsMultipleValues = true;
+}
--- /dev/null
+<?php
+
+namespace wcf\system\page\handler;
+
+use wcf\data\page\Page;
+use wcf\data\person\PersonList;
+use wcf\data\user\online\UserOnline;
+use wcf\system\cache\runtime\PersonRuntimeCache;
+use wcf\system\database\util\PreparedStatementConditionBuilder;
+use wcf\system\WCF;
+
+/**
+ * Page handler implementation for person page.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\System\Page\Handler
+ */
+class PersonPageHandler extends AbstractLookupPageHandler implements IOnlineLocationPageHandler
+{
+ use TOnlineLocationPageHandler;
+
+ /**
+ * @inheritDoc
+ */
+ public function getLink($objectID)
+ {
+ return PersonRuntimeCache::getInstance()->getObject($objectID)->getLink();
+ }
+
+ /**
+ * Returns the textual description if a user is currently online viewing this page.
+ *
+ * @see IOnlineLocationPageHandler::getOnlineLocation()
+ *
+ * @param Page $page visited page
+ * @param UserOnline $user user online object with request data
+ * @return string
+ */
+ public function getOnlineLocation(Page $page, UserOnline $user)
+ {
+ if ($user->pageObjectID === null) {
+ return '';
+ }
+
+ $person = PersonRuntimeCache::getInstance()->getObject($user->pageObjectID);
+ if ($person === null) {
+ return '';
+ }
+
+ return WCF::getLanguage()->getDynamicVariable('wcf.page.onlineLocation.' . $page->identifier, ['person' => $person]);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function isValid($objectID = null)
+ {
+ return PersonRuntimeCache::getInstance()->getObject($objectID) !== null;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function lookup($searchString)
+ {
+ $conditionBuilder = new PreparedStatementConditionBuilder(false, 'OR');
+ $conditionBuilder->add('person.firstName LIKE ?', ['%' . $searchString . '%']);
+ $conditionBuilder->add('person.lastName LIKE ?', ['%' . $searchString . '%']);
+
+ $personList = new PersonList();
+ $personList->getConditionBuilder()->add($conditionBuilder, $conditionBuilder->getParameters());
+ $personList->readObjects();
+
+ $results = [];
+ foreach ($personList as $person) {
+ $results[] = [
+ 'image' => 'fa-user',
+ 'link' => $person->getLink(),
+ 'objectID' => $person->personID,
+ 'title' => $person->getTitle(),
+ ];
+ }
+
+ return $results;
+ }
+
+ /**
+ * Prepares fetching all necessary data for the textual description if a user is currently online
+ * viewing this page.
+ *
+ * @see IOnlineLocationPageHandler::prepareOnlineLocation()
+ *
+ * @param Page $page visited page
+ * @param UserOnline $user user online object with request data
+ */
+ public function prepareOnlineLocation(Page $page, UserOnline $user)
+ {
+ if ($user->pageObjectID !== null) {
+ PersonRuntimeCache::getInstance()->cacheObjectID($user->pageObjectID);
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<language xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/5.4/language.xsd" languagecode="de">
+ <category name="wcf.acp.box">
+ <item name="wcf.acp.box.boxController.com.woltlab.wcf.personList"><![CDATA[Personen]]></item>
+ </category>
+
+ <category name="wcf.acp.group">
+ <item name="wcf.acp.group.option.admin.content.canManagePeople"><![CDATA[Kann Personen verwalten]]></item>
+ <item name="wcf.acp.group.option.category.mod.person"><![CDATA[Personen]]></item>
+ <item name="wcf.acp.group.option.category.user.person"><![CDATA[Personen]]></item>
+ <item name="wcf.acp.group.option.mod.person.canDeleteComment"><![CDATA[Kann Kommentare löschen]]></item>
+ <item name="wcf.acp.group.option.mod.person.canEditComment"><![CDATA[Kann Kommentare bearbeiten]]></item>
+ <item name="wcf.acp.group.option.mod.person.canModerateComment"><![CDATA[Kann Kommentare moderieren]]></item>
+ <item name="wcf.acp.group.option.user.person.canAddComment"><![CDATA[Kann Kommentare erstellen]]></item>
+ <item name="wcf.acp.group.option.user.person.canDeleteComment"><![CDATA[Kann eigene Kommentare löschen]]></item>
+ <item name="wcf.acp.group.option.user.person.canEditComment"><![CDATA[Kann eigene Kommentare bearbeiten]]></item>
+ </category>
+
+ <category name="wcf.acp.menu">
+ <item name="wcf.acp.menu.link.person"><![CDATA[Personen]]></item>
+ <item name="wcf.acp.menu.link.person.add"><![CDATA[Person hinzufügen]]></item>
+ <item name="wcf.acp.menu.link.person.list"><![CDATA[Personen]]></item>
+ </category>
+
+ <category name="wcf.acp.person">
+ <item name="wcf.acp.person.add"><![CDATA[Person hinzufügen]]></item>
+ <item name="wcf.acp.person.edit"><![CDATA[Person bearbeiten]]></item>
+ <item name="wcf.acp.person.list"><![CDATA[Personen]]></item>
+ </category>
+
+ <category name="wcf.page">
+ <item name="wcf.page.onlineLocation.com.woltlab.wcf.people.Person"><![CDATA[Person {anchor object=$person}]]></item>
+ </category>
+
+ <category name="wcf.person">
+ <item name="wcf.person.boxList.description.comments"><![CDATA[{plural value=$boxPerson->comments 1='1 Kommentar' other='# Kommentare'}]]></item>
+ <item name="wcf.person.comment"><![CDATA[Person-Kommentar]]></item>
+ <item name="wcf.person.commentResponse"><![CDATA[Antwort auf Person-Kommentar]]></item>
+ <item name="wcf.person.comments"><![CDATA[Kommentare]]></item>
+ <item name="wcf.person.condition.firstName.description"><![CDATA[Mehrere Vornamen müssen durch ein Komma getrennt werden.]]></item>
+ <item name="wcf.person.condition.lastName.description"><![CDATA[Mehrere Nachnamen müssen durch ein Komma getrennt werden.]]></item>
+ <item name="wcf.person.enableComments"><![CDATA[Kommentare aktivieren]]></item>
+ <item name="wcf.person.enableComments.description"><![CDATA[Erlaubt es Benutzern diese Person zu kommentieren.]]></item>
+ <item name="wcf.person.firstName"><![CDATA[Vorname]]></item>
+ <item name="wcf.person.lastName"><![CDATA[Nachname]]></item>
+ <item name="wcf.person.list"><![CDATA[Personen]]></item>
+ </category>
+</language>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<language xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/5.4/language.xsd" languagecode="en">
+ <category name="wcf.acp.box">
+ <item name="wcf.acp.box.boxController.com.woltlab.wcf.personList"><![CDATA[People]]></item>
+ </category>
+
+ <category name="wcf.acp.group">
+ <item name="wcf.acp.group.option.admin.content.canManagePeople"><![CDATA[Can manage people]]></item>
+ <item name="wcf.acp.group.option.category.mod.person"><![CDATA[People]]></item>
+ <item name="wcf.acp.group.option.category.user.person"><![CDATA[People]]></item>
+ <item name="wcf.acp.group.option.mod.person.canDeleteComment"><![CDATA[Can delete comments]]></item>
+ <item name="wcf.acp.group.option.mod.person.canEditComment"><![CDATA[Can edit comments]]></item>
+ <item name="wcf.acp.group.option.mod.person.canModerateComment"><![CDATA[Can moderate comments]]></item>
+ <item name="wcf.acp.group.option.user.person.canAddComment"><![CDATA[Can create comments]]></item>
+ <item name="wcf.acp.group.option.user.person.canDeleteComment"><![CDATA[Can delete their comments]]></item>
+ <item name="wcf.acp.group.option.user.person.canEditComment"><![CDATA[Can edit their comments]]></item>
+ </category>
+
+ <category name="wcf.acp.menu">
+ <item name="wcf.acp.menu.link.person"><![CDATA[People]]></item>
+ <item name="wcf.acp.menu.link.person.add"><![CDATA[Add Person]]></item>
+ <item name="wcf.acp.menu.link.person.list"><![CDATA[People]]></item>
+ </category>
+
+ <category name="wcf.acp.person">
+ <item name="wcf.acp.person.add"><![CDATA[Add Person]]></item>
+ <item name="wcf.acp.person.edit"><![CDATA[Edit Person]]></item>
+ <item name="wcf.acp.person.list"><![CDATA[People]]></item>
+ </category>
+
+ <category name="wcf.page">
+ <item name="wcf.page.onlineLocation.com.woltlab.wcf.people.Person"><![CDATA[Person {anchor object=$person}]]></item>
+ </category>
+
+ <category name="wcf.person">
+ <item name="wcf.person.boxList.description.comments"><![CDATA[{plural value=$boxPerson->comments 1='1 Comment' other='# Comments'}]]></item>
+ <item name="wcf.person.comment"><![CDATA[Person Comment]]></item>
+ <item name="wcf.person.commentResponse"><![CDATA[Reply to Person Comment]]></item>
+ <item name="wcf.person.comments"><![CDATA[Comments]]></item>
+ <item name="wcf.person.condition.firstName.description"><![CDATA[Multiple first names have to be separated by commas.]]></item>
+ <item name="wcf.person.condition.lastName.description"><![CDATA[Multiple last names have to be separated by commas.]]></item>
+ <item name="wcf.person.enableComments"><![CDATA[Allow Comments]]></item>
+ <item name="wcf.person.enableComments.description"><![CDATA[Allow users to comment on this person.]]></item>
+ <item name="wcf.person.firstName"><![CDATA[First Name]]></item>
+ <item name="wcf.person.lastName"><![CDATA[Last Name]]></item>
+ <item name="wcf.person.list"><![CDATA[People]]></item>
+ </category>
+</language>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/5.4/menuItem.xsd">
+ <import>
+ <item identifier="com.woltlab.wcf.people.PersonList">
+ <menu>com.woltlab.wcf.MainMenu</menu>
+ <title language="de">Personen</title>
+ <title language="en">People</title>
+ <page>com.woltlab.wcf.people.PersonList</page>
+ </item>
+ </import>
+</data>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/5.4/objectType.xsd">
+ <import>
+ <type>
+ <name>com.woltlab.wcf.person.personComment</name>
+ <definitionname>com.woltlab.wcf.comment.commentableContent</definitionname>
+ <classname>wcf\system\comment\manager\PersonCommentManager</classname>
+ </type>
+ <type>
+ <name>com.woltlab.wcf.personList</name>
+ <definitionname>com.woltlab.wcf.boxController</definitionname>
+ <classname>wcf\system\box\PersonListBoxController</classname>
+ </type>
+ <type>
+ <name>com.woltlab.wcf.people.firstName</name>
+ <definitionname>com.woltlab.wcf.box.personList.condition</definitionname>
+ <classname>wcf\system\condition\person\PersonFirstNameTextPropertyCondition</classname>
+ </type>
+ <type>
+ <name>com.woltlab.wcf.people.lastName</name>
+ <definitionname>com.woltlab.wcf.box.personList.condition</definitionname>
+ <classname>wcf\system\condition\person\PersonLastNameTextPropertyCondition</classname>
+ </type>
+ </import>
+</data>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/5.4/objectTypeDefinition.xsd">
+ <import>
+ <definition>
+ <name>com.woltlab.wcf.box.personList.condition</name>
+ <interfacename>wcf\system\condition\IObjectListCondition</interfacename>
+ </definition>
+ </import>
+</data>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<package name="com.woltlab.wcf.people" xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/5.4/package.xsd">
+ <packageinformation>
+ <packagename>WoltLab Suite Core Tutorial: People</packagename>
+ <packagedescription>Adds a simple management system for people as part of a tutorial to create packages.</packagedescription>
+ <version>5.4.0</version>
+ <date>2021-04-16</date>
+ </packageinformation>
+
+ <authorinformation>
+ <author>WoltLab GmbH</author>
+ <authorurl>http://www.woltlab.com</authorurl>
+ </authorinformation>
+
+ <requiredpackages>
+ <requiredpackage minversion="5.4.0 Alpha 1">com.woltlab.wcf</requiredpackage>
+ </requiredpackages>
+
+ <excludedpackages>
+ <excludedpackage version="6.0.0 Alpha 1">com.woltlab.wcf</excludedpackage>
+ </excludedpackages>
+
+ <instructions type="install">
+ <instruction type="acpTemplate" />
+ <instruction type="file" />
+ <instruction type="database">acp/database/install_com.woltlab.wcf.people.php</instruction>
+ <instruction type="template" />
+ <instruction type="language" />
+
+ <instruction type="acpMenu" />
+ <instruction type="page" />
+ <instruction type="menuItem" />
+ <instruction type="userGroupOption" />
+ </instructions>
+</package>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/5.4/page.xsd">
+ <import>
+ <page identifier="com.woltlab.wcf.people.PersonList">
+ <pageType>system</pageType>
+ <controller>wcf\page\PersonListPage</controller>
+ <name language="de">Personen-Liste</name>
+ <name language="en">Person List</name>
+
+ <content language="de">
+ <title>Personen</title>
+ </content>
+ <content language="en">
+ <title>People</title>
+ </content>
+ </page>
+ <page identifier="com.woltlab.wcf.people.Person">
+ <pageType>system</pageType>
+ <controller>wcf\page\PersonPage</controller>
+ <handler>wcf\system\page\handler\PersonPageHandler</handler>
+ <name language="de">Person</name>
+ <name language="en">Person</name>
+ <requireObjectID>1</requireObjectID>
+ <parent>com.woltlab.wcf.people.PersonList</parent>
+ </page>
+ </import>
+</data>
--- /dev/null
+<ul class="sidebarItemList">
+ {foreach from=$boxPersonList item=boxPerson}
+ <li class="box24">
+ <span class="icon icon24 fa-user"></span>
+
+ <div class="sidebarItemTitle">
+ <h3>{anchor object=$boxPerson}</h3>
+ {capture assign='__boxPersonDescription'}{lang __optional=true}wcf.person.boxList.description.{$boxSortField}{/lang}{/capture}
+ {if $__boxPersonDescription}
+ <small>{@$__boxPersonDescription}</small>
+ {/if}
+ </div>
+ </li>
+ {/foreach}
+</ul>
--- /dev/null
+{capture assign='pageTitle'}{$person} - {lang}wcf.person.list{/lang}{/capture}
+
+{capture assign='contentTitle'}{$person}{/capture}
+
+{include file='header'}
+
+{if $person->enableComments}
+ {if $commentList|count || $commentCanAdd}
+ <section id="comments" class="section sectionContainerList">
+ <header class="sectionHeader">
+ <h2 class="sectionTitle">
+ {lang}wcf.person.comments{/lang}
+ {if $person->comments}<span class="badge">{#$person->comments}</span>{/if}
+ </h2>
+ </header>
+
+ {include file='__commentJavaScript' commentContainerID='personCommentList'}
+
+ <div class="personComments">
+ <ul id="personCommentList" class="commentList containerList" {*
+ *}data-can-add="{if $commentCanAdd}true{else}false{/if}" {*
+ *}data-object-id="{@$person->personID}" {*
+ *}data-object-type-id="{@$commentObjectTypeID}" {*
+ *}data-comments="{if $person->comments}{@$commentList->countObjects()}{else}0{/if}" {*
+ *}data-last-comment-time="{@$lastCommentTime}" {*
+ *}>
+ {include file='commentListAddComment' wysiwygSelector='personCommentListAddComment'}
+ {include file='commentList'}
+ </ul>
+ </div>
+ </section>
+ {/if}
+{/if}
+
+<footer class="contentFooter">
+ {hascontent}
+ <nav class="contentFooterNavigation">
+ <ul>
+ {content}{event name='contentFooterNavigation'}{/content}
+ </ul>
+ </nav>
+ {/hascontent}
+</footer>
+
+{include file='footer'}
--- /dev/null
+{capture assign='contentTitle'}{lang}wcf.person.list{/lang} <span class="badge">{#$items}</span>{/capture}
+
+{capture assign='headContent'}
+ {if $pageNo < $pages}
+ <link rel="next" href="{link controller='PersonList'}pageNo={@$pageNo+1}{/link}">
+ {/if}
+ {if $pageNo > 1}
+ <link rel="prev" href="{link controller='PersonList'}{if $pageNo > 2}pageNo={@$pageNo-1}{/if}{/link}">
+ {/if}
+ <link rel="canonical" href="{link controller='PersonList'}{if $pageNo > 1}pageNo={@$pageNo}{/if}{/link}">
+{/capture}
+
+{capture assign='sidebarRight'}
+ <section class="box">
+ <form method="post" action="{link controller='PersonList'}{/link}">
+ <h2 class="boxTitle">{lang}wcf.global.sorting{/lang}</h2>
+
+ <div class="boxContent">
+ <dl>
+ <dt></dt>
+ <dd>
+ <select id="sortField" name="sortField">
+ <option value="firstName"{if $sortField == 'firstName'} selected{/if}>{lang}wcf.person.firstName{/lang}</option>
+ <option value="lastName"{if $sortField == 'lastName'} selected{/if}>{lang}wcf.person.lastName{/lang}</option>
+ {event name='sortField'}
+ </select>
+ <select name="sortOrder">
+ <option value="ASC"{if $sortOrder == 'ASC'} selected{/if}>{lang}wcf.global.sortOrder.ascending{/lang}</option>
+ <option value="DESC"{if $sortOrder == 'DESC'} selected{/if}>{lang}wcf.global.sortOrder.descending{/lang}</option>
+ </select>
+ </dd>
+ </dl>
+
+ <div class="formSubmit">
+ <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s">
+ </div>
+ </div>
+ </form>
+ </section>
+{/capture}
+
+{include file='header'}
+
+{hascontent}
+ <div class="paginationTop">
+ {content}
+ {pages print=true assign=pagesLinks controller='PersonList' link="pageNo=%d&sortField=$sortField&sortOrder=$sortOrder"}
+ {/content}
+ </div>
+{/hascontent}
+
+{if $items}
+ <div class="section sectionContainerList">
+ <ol class="containerList personList">
+ {foreach from=$objects item=person}
+ <li>
+ <div class="box48">
+ <span class="icon icon48 fa-user"></span>
+
+ <div class="details personInformation">
+ <div class="containerHeadline">
+ <h3><a href="{$person->getLink()}">{$person}</a></h3>
+ </div>
+
+ {hascontent}
+ <ul class="inlineList commaSeparated">
+ {content}{event name='personData'}{/content}
+ </ul>
+ {/hascontent}
+
+ {hascontent}
+ <dl class="plain inlineDataList small">
+ {content}
+ {if $person->enableComments}
+ <dt>{lang}wcf.person.comments{/lang}</dt>
+ <dd>{#$person->comments}</dd>
+ {/if}
+
+ {event name='personStatistics'}
+ {/content}
+ </dl>
+ {/hascontent}
+ </div>
+ </div>
+ </li>
+ {/foreach}
+ </ol>
+ </div>
+{else}
+ <p class="info">{lang}wcf.global.noItems{/lang}</p>
+{/if}
+
+<footer class="contentFooter">
+ {hascontent}
+ <div class="paginationBottom">
+ {content}{@$pagesLinks}{/content}
+ </div>
+ {/hascontent}
+
+ {hascontent}
+ <nav class="contentFooterNavigation">
+ <ul>
+ {content}{event name='contentFooterNavigation'}{/content}
+ </ul>
+ </nav>
+ {/hascontent}
+</footer>
+
+{include file='footer'}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/5.4/userGroupOption.xsd">
+ <import>
+ <categories>
+ <category name="mod.person">
+ <parent>mod</parent>
+ </category>
+ <category name="user.person">
+ <parent>user</parent>
+ </category>
+ </categories>
+
+ <options>
+ <option name="admin.content.canManagePeople">
+ <categoryname>admin.content</categoryname>
+ <optiontype>boolean</optiontype>
+ <defaultvalue>0</defaultvalue>
+ <admindefaultvalue>1</admindefaultvalue>
+ <usersonly>1</usersonly>
+ </option>
+ <option name="mod.person.canModerateComment">
+ <categoryname>mod.person</categoryname>
+ <optiontype>boolean</optiontype>
+ <defaultvalue>0</defaultvalue>
+ <moddefaultvalue>1</moddefaultvalue>
+ <usersonly>1</usersonly>
+ </option>
+ <option name="mod.person.canEditComment">
+ <categoryname>mod.person</categoryname>
+ <optiontype>boolean</optiontype>
+ <defaultvalue>0</defaultvalue>
+ <moddefaultvalue>1</moddefaultvalue>
+ <usersonly>1</usersonly>
+ </option>
+ <option name="mod.person.canDeleteComment">
+ <categoryname>mod.person</categoryname>
+ <optiontype>boolean</optiontype>
+ <defaultvalue>0</defaultvalue>
+ <moddefaultvalue>1</moddefaultvalue>
+ <usersonly>1</usersonly>
+ </option>
+ <option name="user.person.canAddComment">
+ <categoryname>user.person</categoryname>
+ <optiontype>boolean</optiontype>
+ <defaultvalue>1</defaultvalue>
+ <enableoptions>user.person.canAddCommentWithoutModeration</enableoptions>
+ <excludedInTinyBuild>1</excludedInTinyBuild>
+ </option>
+ <option name="user.person.canAddCommentWithoutModeration">
+ <categoryname>user.person</categoryname>
+ <optiontype>boolean</optiontype>
+ <defaultvalue>1</defaultvalue>
+ <excludedInTinyBuild>1</excludedInTinyBuild>
+ </option>
+ <option name="user.person.canEditComment">
+ <categoryname>user.person</categoryname>
+ <optiontype>boolean</optiontype>
+ <defaultvalue>1</defaultvalue>
+ <usersonly>1</usersonly>
+ </option>
+ <option name="user.person.canDeleteComment">
+ <categoryname>user.person</categoryname>
+ <optiontype>boolean</optiontype>
+ <defaultvalue>0</defaultvalue>
+ <admindefaultvalue>1</admindefaultvalue>
+ <usersonly>1</usersonly>
+ </option>
+ </options>
+ </import>
+</data>