Skip to content

Commit 9ffa897

Browse files
author
Matthias Schmidt
committed
Add source code for part 6 of tutorial series
1 parent f4bed51 commit 9ffa897

File tree

45 files changed

+2723
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2723
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<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">
3+
<import>
4+
<acpmenuitem name="wcf.acp.menu.link.person">
5+
<parent>wcf.acp.menu.link.content</parent>
6+
</acpmenuitem>
7+
<acpmenuitem name="wcf.acp.menu.link.person.list">
8+
<controller>wcf\acp\page\PersonListPage</controller>
9+
<parent>wcf.acp.menu.link.person</parent>
10+
<permissions>admin.content.canManagePeople</permissions>
11+
</acpmenuitem>
12+
<acpmenuitem name="wcf.acp.menu.link.person.add">
13+
<controller>wcf\acp\form\PersonAddForm</controller>
14+
<parent>wcf.acp.menu.link.person.list</parent>
15+
<permissions>admin.content.canManagePeople</permissions>
16+
<icon>fa-plus</icon>
17+
</acpmenuitem>
18+
</import>
19+
</data>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{include file='header' pageTitle='wcf.acp.person.'|concat:$action}
2+
3+
<header class="contentHeader">
4+
<div class="contentHeaderTitle">
5+
<h1 class="contentTitle">{lang}wcf.acp.person.{$action}{/lang}</h1>
6+
</div>
7+
8+
<nav class="contentHeaderNavigation">
9+
<ul>
10+
<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>
11+
12+
{event name='contentHeaderNavigation'}
13+
</ul>
14+
</nav>
15+
</header>
16+
17+
{@$form->getHtml()}
18+
19+
{include file='footer'}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
{include file='header' pageTitle='wcf.acp.person.list'}
2+
3+
<header class="contentHeader">
4+
<div class="contentHeaderTitle">
5+
<h1 class="contentTitle">{lang}wcf.acp.person.list{/lang}</h1>
6+
</div>
7+
8+
<nav class="contentHeaderNavigation">
9+
<ul>
10+
<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>
11+
12+
{event name='contentHeaderNavigation'}
13+
</ul>
14+
</nav>
15+
</header>
16+
17+
{hascontent}
18+
<div class="paginationTop">
19+
{content}{pages print=true assign=pagesLinks controller="PersonList" link="pageNo=%d&sortField=$sortField&sortOrder=$sortOrder"}{/content}
20+
</div>
21+
{/hascontent}
22+
23+
{if $objects|count}
24+
<div class="section tabularBox">
25+
<table class="table jsObjectActionContainer" data-object-action-class-name="wcf\data\person\PersonAction">
26+
<thead>
27+
<tr>
28+
<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>
29+
<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>
30+
<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>
31+
32+
{event name='columnHeads'}
33+
</tr>
34+
</thead>
35+
36+
<tbody class="jsReloadPageWhenEmpty">
37+
{foreach from=$objects item=person}
38+
<tr class="jsObjectActionObject" data-object-id="{@$person->getObjectID()}">
39+
<td class="columnIcon">
40+
<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>
41+
{objectAction action="delete" objectTitle=$person->getTitle()}
42+
43+
{event name='rowButtons'}
44+
</td>
45+
<td class="columnID">{#$person->personID}</td>
46+
<td class="columnTitle columnFirstName"><a href="{link controller='PersonEdit' object=$person}{/link}">{$person->firstName}</a></td>
47+
<td class="columnTitle columnLastName"><a href="{link controller='PersonEdit' object=$person}{/link}">{$person->lastName}</a></td>
48+
49+
{event name='columns'}
50+
</tr>
51+
{/foreach}
52+
</tbody>
53+
</table>
54+
</div>
55+
56+
<footer class="contentFooter">
57+
{hascontent}
58+
<div class="paginationBottom">
59+
{content}{@$pagesLinks}{/content}
60+
</div>
61+
{/hascontent}
62+
63+
<nav class="contentFooterNavigation">
64+
<ul>
65+
<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>
66+
67+
{event name='contentFooterNavigation'}
68+
</ul>
69+
</nav>
70+
</footer>
71+
{else}
72+
<p class="info">{lang}wcf.global.noItems{/lang}</p>
73+
{/if}
74+
75+
{include file='footer'}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<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/eventListener.xsd">
3+
<import>
4+
<eventlistener name="rename@wcf\data\user\UserAction">
5+
<eventclassname>wcf\data\user\UserAction</eventclassname>
6+
<eventname>rename</eventname>
7+
<listenerclassname>wcf\system\event\listener\PersonUserActionRenameListener</listenerclassname>
8+
<environment>all</environment>
9+
</eventlistener>
10+
<eventlistener name="save@wcf\acp\form\UserMergeForm">
11+
<eventclassname>wcf\acp\form\UserMergeForm</eventclassname>
12+
<eventname>save</eventname>
13+
<listenerclassname>wcf\system\event\listener\PersonUserMergeListener</listenerclassname>
14+
<environment>admin</environment>
15+
</eventlistener>
16+
<eventlistener name="execute@wcf\system\cronjob\PruneIpAddressesCronjob">
17+
<eventclassname>wcf\system\cronjob\PruneIpAddressesCronjob</eventclassname>
18+
<eventname>execute</eventname>
19+
<listenerclassname>wcf\system\event\listener\PersonPruneIpAddressesCronjobListener</listenerclassname>
20+
<environment>all</environment>
21+
</eventlistener>
22+
<eventlistener name="export@wcf\acp\action\UserExportGdprAction">
23+
<eventclassname>wcf\acp\action\UserExportGdprAction</eventclassname>
24+
<eventname>export</eventname>
25+
<listenerclassname>wcf\system\event\listener\PersonUserExportGdprListener</listenerclassname>
26+
<environment>admin</environment>
27+
</eventlistener>
28+
<eventlistener name="execute@wcf\system\worker\UserActivityPointItemsRebuildDataWorker">
29+
<eventclassname>wcf\system\worker\UserActivityPointItemsRebuildDataWorker</eventclassname>
30+
<eventname>execute</eventname>
31+
<listenerclassname>wcf\system\event\listener\PersonUserActivityPointItemsRebuildDataWorkerListener</listenerclassname>
32+
<environment>admin</environment>
33+
</eventlistener>
34+
</import>
35+
</data>
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
use wcf\system\database\table\column\DefaultTrueBooleanDatabaseTableColumn;
4+
use wcf\system\database\table\column\IntDatabaseTableColumn;
5+
use wcf\system\database\table\column\NotNullInt10DatabaseTableColumn;
6+
use wcf\system\database\table\column\NotNullVarchar255DatabaseTableColumn;
7+
use wcf\system\database\table\column\ObjectIdDatabaseTableColumn;
8+
use wcf\system\database\table\column\SmallintDatabaseTableColumn;
9+
use wcf\system\database\table\column\TextDatabaseTableColumn;
10+
use wcf\system\database\table\column\VarcharDatabaseTableColumn;
11+
use wcf\system\database\table\DatabaseTable;
12+
use wcf\system\database\table\index\DatabaseTableForeignKey;
13+
14+
return [
15+
DatabaseTable::create('wcf1_person')
16+
->columns([
17+
ObjectIdDatabaseTableColumn::create('personID'),
18+
NotNullVarchar255DatabaseTableColumn::create('firstName'),
19+
NotNullVarchar255DatabaseTableColumn::create('lastName'),
20+
NotNullInt10DatabaseTableColumn::create('informationCount')
21+
->defaultValue(0),
22+
SmallintDatabaseTableColumn::create('comments')
23+
->length(5)
24+
->notNull()
25+
->defaultValue(0),
26+
DefaultTrueBooleanDatabaseTableColumn::create('enableComments'),
27+
]),
28+
29+
DatabaseTable::create('wcf1_person_information')
30+
->columns([
31+
ObjectIdDatabaseTableColumn::create('informationID'),
32+
NotNullInt10DatabaseTableColumn::create('personID'),
33+
TextDatabaseTableColumn::create('information'),
34+
IntDatabaseTableColumn::create('userID')
35+
->length(10),
36+
NotNullVarchar255DatabaseTableColumn::create('username'),
37+
VarcharDatabaseTableColumn::create('ipAddress')
38+
->length(39)
39+
->notNull(true)
40+
->defaultValue(''),
41+
NotNullInt10DatabaseTableColumn::create('time'),
42+
])
43+
->foreignKeys([
44+
DatabaseTableForeignKey::create()
45+
->columns(['personID'])
46+
->referencedTable('wcf1_person')
47+
->referencedColumns(['personID'])
48+
->onDelete('CASCADE'),
49+
DatabaseTableForeignKey::create()
50+
->columns(['userID'])
51+
->referencedTable('wcf1_user')
52+
->referencedColumns(['userID'])
53+
->onDelete('SET NULL'),
54+
]),
55+
];
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* Provides the JavaScript code for the person page.
3+
*
4+
* @author Matthias Schmidt
5+
* @copyright 2001-2021 WoltLab GmbH
6+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
7+
* @module WoltLabSuite/Core/Controller/Person
8+
*/
9+
define(["require", "exports", "tslib", "WoltLabSuite/Core/Form/Builder/Dialog", "WoltLabSuite/Core/Language", "WoltLabSuite/Core/Ui/Notification"], function (require, exports, tslib_1, Dialog_1, Language, UiNotification) {
10+
"use strict";
11+
Object.defineProperty(exports, "__esModule", { value: true });
12+
exports.init = void 0;
13+
Dialog_1 = tslib_1.__importDefault(Dialog_1);
14+
Language = tslib_1.__importStar(Language);
15+
UiNotification = tslib_1.__importStar(UiNotification);
16+
let addDialog;
17+
const editDialogs = new Map();
18+
/**
19+
* Opens the edit dialog after clicking on the edit button for a piece of information.
20+
*/
21+
function editInformation(event) {
22+
event.preventDefault();
23+
const currentTarget = event.currentTarget;
24+
const information = currentTarget.closest(".jsObjectActionObject");
25+
const informationId = information.dataset.objectId;
26+
if (!editDialogs.has(informationId)) {
27+
editDialogs.set(informationId, new Dialog_1.default(`personInformationEditDialog${informationId}`, "wcf\\data\\person\\information\\PersonInformationAction", "getEditDialog", {
28+
actionParameters: {
29+
informationID: informationId,
30+
},
31+
dialog: {
32+
title: Language.get("wcf.person.information.edit"),
33+
},
34+
submitActionName: "submitEditDialog",
35+
successCallback(returnValues) {
36+
document.getElementById(`personInformation${returnValues.informationID}`).innerHTML =
37+
returnValues.formattedInformation;
38+
UiNotification.show(Language.get("wcf.person.information.edit.success"));
39+
},
40+
}));
41+
}
42+
editDialogs.get(informationId).open();
43+
}
44+
/**
45+
* Initializes the JavaScript code for the person page.
46+
*/
47+
function init(personId, options) {
48+
if (options.canAddInformation) {
49+
// Initialize the dialog to add new information.
50+
addDialog = new Dialog_1.default("personInformationAddDialog", "wcf\\data\\person\\information\\PersonInformationAction", "getAddDialog", {
51+
actionParameters: {
52+
personID: personId,
53+
},
54+
dialog: {
55+
title: Language.get("wcf.person.information.add"),
56+
},
57+
submitActionName: "submitAddDialog",
58+
successCallback() {
59+
UiNotification.show(Language.get("wcf.person.information.add.success"), () => window.location.reload());
60+
},
61+
});
62+
document.getElementById("personInformationAddButton").addEventListener("click", (event) => {
63+
event.preventDefault();
64+
addDialog.open();
65+
});
66+
}
67+
document
68+
.querySelectorAll(".jsEditInformation")
69+
.forEach((el) => el.addEventListener("click", (ev) => editInformation(ev)));
70+
}
71+
exports.init = init;
72+
});
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
namespace wcf\acp\form;
4+
5+
use wcf\data\person\PersonAction;
6+
use wcf\form\AbstractFormBuilderForm;
7+
use wcf\system\form\builder\container\FormContainer;
8+
use wcf\system\form\builder\field\BooleanFormField;
9+
use wcf\system\form\builder\field\TextFormField;
10+
11+
/**
12+
* Shows the form to create a new person.
13+
*
14+
* @author Matthias Schmidt
15+
* @copyright 2001-2021 WoltLab GmbH
16+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
17+
* @package WoltLabSuite\Core\Acp\Form
18+
*/
19+
class PersonAddForm extends AbstractFormBuilderForm
20+
{
21+
/**
22+
* @inheritDoc
23+
*/
24+
public $activeMenuItem = 'wcf.acp.menu.link.person.add';
25+
26+
/**
27+
* @inheritDoc
28+
*/
29+
public $formAction = 'create';
30+
31+
/**
32+
* @inheritDoc
33+
*/
34+
public $neededPermissions = ['admin.content.canManagePeople'];
35+
36+
/**
37+
* @inheritDoc
38+
*/
39+
public $objectActionClass = PersonAction::class;
40+
41+
/**
42+
* @inheritDoc
43+
*/
44+
public $objectEditLinkController = PersonEditForm::class;
45+
46+
/**
47+
* @inheritDoc
48+
*/
49+
protected function createForm()
50+
{
51+
parent::createForm();
52+
53+
$this->form->appendChild(
54+
FormContainer::create('data')
55+
->label('wcf.global.form.data')
56+
->appendChildren([
57+
TextFormField::create('firstName')
58+
->label('wcf.person.firstName')
59+
->required()
60+
->autoFocus()
61+
->maximumLength(255),
62+
63+
TextFormField::create('lastName')
64+
->label('wcf.person.lastName')
65+
->required()
66+
->maximumLength(255),
67+
68+
BooleanFormField::create('enableComments')
69+
->label('wcf.person.enableComments')
70+
->description('wcf.person.enableComments.description')
71+
->value(true),
72+
])
73+
);
74+
}
75+
}

0 commit comments

Comments
 (0)