Browse code

Change bundle structure

Sebastian Zoglowek authored on14/08/2022 15:51:15
Showing61 changed files
... ...
@@ -2,13 +2,13 @@
2 2
     "name": "oveleon/contao-member-extension-bundle",
3 3
     "type": "contao-bundle",
4 4
     "description": "Member feature extension for Contao.",
5
+    "license": "MIT",
5 6
     "keywords": ["contao","member-extension-bundle"],
6 7
     "homepage": "https://oveleon.de/",
7
-    "license": "MIT",
8 8
     "authors": [
9 9
         {
10
-            "name": "Oveleon",
11
-            "homepage": "https://oveleon.de/",
10
+            "name": "Sebastian Zoglowek",
11
+            "homepage": "https://github.com/zoglo",
12 12
             "role": "Developer"
13 13
         },
14 14
         {
... ...
@@ -20,11 +20,6 @@
20 20
             "name": "Fabian Ekert",
21 21
             "homepage": "https://github.com/eki89",
22 22
             "role": "Developer"
23
-        },
24
-        {
25
-            "name": "Sebastian Zoglowek",
26
-            "homepage": "https://github.com/zoglo",
27
-            "role": "Developer"
28 23
         }
29 24
     ],
30 25
     "require": {
... ...
@@ -38,33 +33,28 @@
38 33
         "contao/core": "*",
39 34
         "contao/manager-plugin": "<2.0 || >=3.0"
40 35
     },
36
+    "extra": {
37
+        "branch-alias": {
38
+            "dev-master": "1.2.x-dev"
39
+        },
40
+        "contao-manager-plugin": "Oveleon\\ContaoMemberExtensionBundle\\ContaoManager\\Plugin"
41
+    },
41 42
     "autoload": {
42 43
         "psr-4": {
43 44
             "Oveleon\\ContaoMemberExtensionBundle\\": "src/"
44 45
         },
45 46
         "classmap": [
46
-            "src/Resources/contao/"
47
+            "contao/"
47 48
         ],
48 49
         "exclude-from-classmap": [
49
-            "src/Resources/contao/config/",
50
-            "src/Resources/contao/dca/",
51
-            "src/Resources/contao/languages/",
52
-            "src/Resources/contao/templates/"
50
+            "contao/config/",
51
+            "contao/dca/",
52
+            "contao/languages/",
53
+            "contao/templates/"
53 54
         ]
54 55
     },
55
-    "extra": {
56
-        "branch-alias": {
57
-            "dev-master": "1.2.x-dev"
58
-        },
59
-        "contao-manager-plugin": "Oveleon\\ContaoMemberExtensionBundle\\ContaoManager\\Plugin"
60
-    },
61
-    "config": {
62
-        "allow-plugins": {
63
-            "contao-components/installer": true,
64
-            "contao/manager-plugin": true
65
-        }
66
-    },
67 56
     "support": {
68
-        "issues": "https://github.com/oveleon/contao-member-extension-bundle/issues"
57
+        "issues": "https://github.com/oveleon/contao-member-extension-bundle/issues",
58
+        "source": "https://github.com/oveleon/contao-member-extension-bundle"
69 59
     }
70
-}
71 60
\ No newline at end of file
61
+}
72 62
new file mode 100644
... ...
@@ -0,0 +1,8 @@
1
+services:
2
+    contao_member.listener.insert_tags:
3
+        class: Oveleon\ContaoMemberExtensionBundle\EventListener\InsertTagsListener
4
+        arguments:
5
+            - '@contao.framework'
6
+        tags:
7
+          - { name: contao.hook, hook: replaceInsertTags }
8
+        public: true
0 9
new file mode 100644
... ...
@@ -0,0 +1,323 @@
1
+<?php
2
+
3
+declare(strict_types=1);
4
+
5
+/*
6
+ * This file is part of Oveleon ContaoMemberExtension Bundle.
7
+ *
8
+ * @package     contao-member-extension-bundle
9
+ * @license     MIT
10
+ * @author      Daniele Sciannimanica   <https://github.com/doishub>
11
+ * @author      Fabian Ekert            <https://github.com/eki89>
12
+ * @author      Sebastian Zoglowek      <https://github.com/zoglo>
13
+ * @copyright   Oveleon                 <https://www.oveleon.de/>
14
+ */
15
+
16
+namespace Oveleon\ContaoMemberExtensionBundle;
17
+
18
+use Contao\Config;
19
+use Contao\CoreBundle\Monolog\ContaoContext;
20
+use Contao\Dbafs;
21
+use Contao\File;
22
+use Contao\FilesModel;
23
+use Contao\FileUpload;
24
+use Contao\Frontend;
25
+use Contao\FrontendUser;
26
+use Contao\MemberModel;
27
+use Contao\StringUtil;
28
+use Contao\System;
29
+use Contao\Validator;
30
+use Psr\Log\LogLevel;
31
+
32
+
33
+/**
34
+ * Class Member
35
+ *
36
+ * @property int $avatar UUID of the avatar
37
+ */
38
+class Member extends Frontend
39
+{
40
+    const DEFAULT_PICTURE = 'bundles/contaomemberextension/avatar.png';
41
+
42
+    /**
43
+     * MemberAvatar file name
44
+     */
45
+    protected string $avatarName = 'memberAvatar';
46
+
47
+    /**
48
+     * Create avatar for a member | Registration
49
+     */
50
+    public function createAvatar(int $userId, array $arrData): void
51
+    {
52
+        $objMember = MemberModel::findById($userId);
53
+        $this->processAvatar($objMember, $arrData);
54
+    }
55
+
56
+    /**
57
+     * Update avatar of a member | Login
58
+     */
59
+    public function updateAvatar(FrontendUser $objUser, array $arrData): void
60
+    {
61
+        $objMember = MemberModel::findById($objUser->id);
62
+        $this->processAvatar($objMember, $arrData);
63
+    }
64
+
65
+    /**
66
+     * Process avatar upload for a member
67
+     */
68
+    protected function processAvatar(MemberModel $objMember, ?array $arrData): void
69
+    {
70
+        $objMember = MemberModel::findByPk($objMember->id);
71
+
72
+        if ($objMember === null)
73
+        {
74
+            return;
75
+        }
76
+
77
+        $file = $_SESSION['FILES']['avatar'];
78
+        $maxlength_kb = $this->getMaximumUploadSize();
79
+        $maxlength_kb_readable = $this->getReadableSize($maxlength_kb);
80
+
81
+        // Sanitize the filename
82
+        try
83
+        {
84
+            $file['name'] = StringUtil::sanitizeFileName($file['name']);
85
+        }
86
+        catch (\InvalidArgumentException $e)
87
+        {
88
+            // ToDo: add error message for invalid characters
89
+            return;
90
+        }
91
+
92
+        // Invalid file name
93
+        if (!Validator::isValidFileName($file['name']))
94
+        {
95
+            // ToDo: add error message for invalid characters
96
+            return;
97
+        }
98
+
99
+        // File was not uploaded
100
+        if (!is_uploaded_file($file['tmp_name']))
101
+        {
102
+            // ToDo: Add error messages
103
+            /*if ($file['error'] == 1 || $file['error'] == 2) { // Add error message for maximum file size }
104
+            elseif ($file['error'] == 3) { // Add error message for partial upload }
105
+            elseif ($file['error'] > 0) { // Add error message for failed upload }*/
106
+
107
+            unset($_SESSION['FILES']['avatar']);
108
+
109
+            return;
110
+        }
111
+
112
+        // File is too big
113
+        if ($file['size'] > $maxlength_kb)
114
+        {
115
+            // ToDo: add error message for maximum file size
116
+            unset($_SESSION['FILES']['avatar']);
117
+
118
+            return;
119
+        }
120
+
121
+        $objFile = new File($file['name']);
122
+        $uploadTypes = StringUtil::trimsplit(',', \Config::get('validImageTypes'));
123
+
124
+        // File type is not allowed
125
+        if (!\in_array($objFile->extension, $uploadTypes))
126
+        {
127
+            // ToDo: add error message for not allowed file type
128
+            unset($_SESSION['FILES']['avatar']);
129
+
130
+            return;
131
+        }
132
+
133
+        if ($arrImageSize = @getimagesize($file['tmp_name']))
134
+        {
135
+            $intImageWidth = Config::get('imageWidth');
136
+
137
+            // Image exceeds maximum image width
138
+            if ($intImageWidth > 0 && $arrImageSize[0] > $intImageWidth) {
139
+                // ToDo: add error message for exceeding width
140
+                unset($_SESSION['FILES']['avatar']);
141
+
142
+                return;
143
+            }
144
+
145
+            $intImageHeight = Config::get('imageHeight');
146
+
147
+            // Image exceeds maximum image height
148
+            if ($intImageHeight > 0 && $arrImageSize[1] > $intImageHeight) {
149
+                // ToDo: add error message for exceeding height
150
+                unset($_SESSION['FILES']['avatar']);
151
+
152
+                return;
153
+            }
154
+        }
155
+
156
+        // Upload valid file type with no width and height -> svg
157
+
158
+        // Don't upload if no homedir is assigned
159
+        // ToDo: Create homedir?
160
+        if (!$objMember->assignDir || !$objMember->homeDir)
161
+        {
162
+            // ToDo: add error message for no homedir
163
+            return;
164
+        }
165
+
166
+        $intUploadFolder = $objMember->homeDir;
167
+
168
+        $objUploadFolder = FilesModel::findByUuid($intUploadFolder);
169
+
170
+        // The upload folder could not be found
171
+        if ($objUploadFolder === null)
172
+        {
173
+            throw new Exception("Invalid upload folder ID $intUploadFolder");
174
+        }
175
+
176
+        $strUploadFolder = $objUploadFolder->path;
177
+
178
+        // Store the file if the upload folder exists
179
+        $projectDir = System::getContainer()->getParameter('kernel.project_dir');
180
+
181
+        if (!!$strUploadFolder & is_dir($projectDir . '/' . $strUploadFolder))
182
+        {
183
+            // Delete existing avatar if it exists
184
+            $this->deleteAvatar($objMember);
185
+
186
+            $this->import('Files');
187
+
188
+            // Rename file
189
+            $file['name'] =  $this->avatarName . '.' . $objFile->extension;
190
+
191
+            // Move the file to its destination
192
+            $this->Files->move_uploaded_file($file['tmp_name'], $strUploadFolder . '/' . $file['name']);
193
+            $this->Files->chmod($strUploadFolder . '/' . $file['name'], 0666 & ~umask());
194
+
195
+            $strUuid = null;
196
+            $strFile = $strUploadFolder . '/' . $file['name'];
197
+
198
+
199
+            // Generate the DB entries
200
+            if (Dbafs::shouldBeSynchronized($strFile))
201
+            {
202
+                $objModel = FilesModel::findByPath($strFile);
203
+
204
+                if ($objModel === null)
205
+                {
206
+                    $objModel = Dbafs::addResource($strFile);
207
+                }
208
+
209
+                $strUuid = StringUtil::binToUuid($objModel->uuid);
210
+
211
+                // Update the hash of the target folder
212
+                Dbafs::updateFolderHashes($strUploadFolder);
213
+
214
+                // Update member avatar
215
+                $objMember->avatar = $objModel->uuid;
216
+                $objMember->save();
217
+            }
218
+
219
+            // Add the session entry
220
+            $_SESSION['FILES']['avatar'] = array
221
+            (
222
+                'name'     => $file['name'],
223
+                'type'     => $file['type'],
224
+                'tmp_name' => $projectDir . '/' . $strFile,
225
+                'error'    => $file['error'],
226
+                'size'     => $file['size'],
227
+                'uploaded' => true,
228
+                'uuid'     => $strUuid
229
+            );
230
+
231
+            // Add a log entry
232
+            $logger = System::getContainer()->get('monolog.logger.contao');
233
+            $logger->log(LogLevel::INFO, 'File "' . $strUploadFolder . '/' . $file['name'] . '" has been uploaded', ['contao' => new ContaoContext(__METHOD__, TL_FILES)]);
234
+        }
235
+
236
+        unset($_SESSION['FILES']['avatar']);
237
+    }
238
+
239
+    /**
240
+     * Return the maximum upload file size in bytes
241
+     */
242
+    protected function getMaximumUploadSize(): string
243
+    {
244
+        if ($this->maxlength > 0)
245
+        {
246
+            return $this->maxlength;
247
+        }
248
+
249
+        return FileUpload::getMaxUploadSize();
250
+    }
251
+
252
+    /**
253
+     * Parses an avatar to the template
254
+     */
255
+    public static function parseMemberAvatar(?MemberModel $objMember, &$objTemplate, $strImgSize): void
256
+    {
257
+        $objTemplate->addImage= true;
258
+
259
+        $objTemplate->singleSRC = self::DEFAULT_PICTURE;
260
+        $objTemplate->addFallbackImage = true;
261
+
262
+        $projectDir = System::getContainer()->getParameter('kernel.project_dir');
263
+
264
+        // Check if member avatar exists
265
+        if(null === $objMember || null === $objMember->avatar || null === ($objFile = FilesModel::findByUuid($objMember->avatar)) || !\is_file($projectDir.'/'.$objFile->path))
266
+        {
267
+            $objFile = !!($uuidDefault = Config::get('defaultAvatar')) ? FilesModel::findByUuid($uuidDefault) : null;
268
+        }
269
+
270
+        // Check if config avatar exists
271
+        if (null === $objFile || !\is_file($projectDir . '/' . $objFile->path))
272
+        {
273
+            return;
274
+        }
275
+
276
+        $objTemplate->addFallbackImage = false;
277
+        $arrData = ['singleSRC'=>$objFile->path, 'size'=>$strImgSize];
278
+
279
+        //ToDo: Change to FigureBuilder in the future
280
+        $objTemplate->addImageToTemplate($objTemplate, $arrData, null, null, $objFile);
281
+    }
282
+
283
+    /**
284
+     * Gets the url for a member avatar
285
+     */
286
+    public static function getMemberAvatarURL(?MemberModel $objMember): string
287
+    {
288
+        // ToDo: Merge logic with parseMemberAvatar
289
+        $projectDir = System::getContainer()->getParameter('kernel.project_dir');
290
+
291
+        if(null === $objMember || null === $objMember->avatar || null === ($objFile = FilesModel::findByUuid($objMember->avatar)) || !\is_file($projectDir.'/'. $objFile->path))
292
+        {
293
+            $objFile = !!($uuidDefault = Config::get('defaultAvatar')) ? FilesModel::findByUuid($uuidDefault) : null;
294
+        }
295
+
296
+        // Check if config avatar exists
297
+        if (null === $objFile || !\is_file($projectDir . '/' . $objFile->path))
298
+        {
299
+            return self::DEFAULT_PICTURE;
300
+        }
301
+
302
+        return $objFile->path;
303
+    }
304
+
305
+    /**
306
+     * Deletes an avatar
307
+     */
308
+    public static function deleteAvatar(MemberModel $objMember): void
309
+    {
310
+        if(!!$objMember->avatar)
311
+        {
312
+            $objFile = FilesModel::findByUuid($objMember->avatar) ?: '';
313
+            $projectDir = System::getContainer()->getParameter('kernel.project_dir');
314
+
315
+            // Only delete if file exists
316
+            if (!!$objFile && file_exists($projectDir . '/' . $objFile->path))
317
+            {
318
+                $file = new File($objFile->path);
319
+                $file->delete();
320
+            }
321
+        }
322
+    }
323
+}
0 324
new file mode 100644
... ...
@@ -0,0 +1,38 @@
1
+<?php
2
+
3
+declare(strict_types=1);
4
+
5
+/*
6
+ * This file is part of Oveleon ContaoMemberExtension Bundle.
7
+ *
8
+ * @package     contao-member-extension-bundle
9
+ * @license     MIT
10
+ * @author      Daniele Sciannimanica   <https://github.com/doishub>
11
+ * @author      Fabian Ekert            <https://github.com/eki89>
12
+ * @author      Sebastian Zoglowek      <https://github.com/zoglo>
13
+ * @copyright   Oveleon                 <https://www.oveleon.de/>
14
+ */
15
+
16
+// Back end modules
17
+use Contao\System;
18
+
19
+$GLOBALS['BE_MOD']['system']['member_settings'] = [
20
+    'tables'            => ['tl_member_settings'],
21
+    'hideInNavigation'  => true,
22
+];
23
+
24
+// Front end modules
25
+// ToDo: Change to ArrayUtil::arrayInsert when Contao 4.9 support ends
26
+array_insert($GLOBALS['FE_MOD']['user'], -1, [
27
+    'avatar'       => 'Oveleon\ContaoMemberExtensionBundle\ModuleAvatar',
28
+    'deleteAvatar' => 'Oveleon\ContaoMemberExtensionBundle\ModuleDeleteAvatar',
29
+    'memberList'   => 'Oveleon\ContaoMemberExtensionBundle\ModuleMemberList',
30
+    'memberReader' => 'Oveleon\ContaoMemberExtensionBundle\ModuleMemberReader'
31
+]);
32
+
33
+// Register hooks
34
+$GLOBALS['TL_HOOKS']['createNewUser'][] = ['Oveleon\ContaoMemberExtensionBundle\Member', 'createAvatar'];
35
+$GLOBALS['TL_HOOKS']['updatePersonalData'][] = ['Oveleon\ContaoMemberExtensionBundle\Member', 'updateAvatar'];
36
+
37
+// Style sheet
38
+$request = System::getContainer()->get('request_stack')->getCurrentRequest();
0 39
new file mode 100644
... ...
@@ -0,0 +1,40 @@
1
+<?php
2
+
3
+declare(strict_types=1);
4
+
5
+/*
6
+ * This file is part of Oveleon ContaoMemberExtension Bundle.
7
+ *
8
+ * @package     contao-member-extension-bundle
9
+ * @license     MIT
10
+ * @author      Daniele Sciannimanica   <https://github.com/doishub>
11
+ * @author      Fabian Ekert            <https://github.com/eki89>
12
+ * @author      Sebastian Zoglowek      <https://github.com/zoglo>
13
+ * @copyright   Oveleon                 <https://www.oveleon.de/>
14
+ */
15
+
16
+use Contao\Config;
17
+use Contao\CoreBundle\DataContainer\PaletteManipulator;
18
+
19
+// Extend the default palette
20
+PaletteManipulator::create()
21
+    ->addField(['avatar'], 'personal_legend', PaletteManipulator::POSITION_APPEND)
22
+    ->applyToPalette('default', 'tl_member')
23
+;
24
+
25
+// Add global operations
26
+$GLOBALS['TL_DCA']['tl_member']['list']['global_operations']['settings'] = [
27
+    'label' => &$GLOBALS['TL_LANG']['tl_member']['settings'],
28
+    'href' => 'do=member_settings',
29
+    'icon' => 'edit.svg',
30
+    'attributes' => 'onclick="Backend.getScrollOffset()" accesskey="e"'
31
+];
32
+
33
+// Add fields to tl_user
34
+$GLOBALS['TL_DCA']['tl_member']['fields']['avatar'] = [
35
+    'label' => &$GLOBALS['TL_LANG']['tl_member']['avatar'],
36
+    'exclude' => true,
37
+    'inputType' => 'fileTree',
38
+    'eval' => ['feEditable'=>true, 'feViewable'=>true, 'feGroup'=>'personal', 'fieldType'=>'radio', 'filesOnly'=>true, 'isGallery'=>true, 'extensions'=>Config::get('validImageTypes'), 'tl_class'=>'clr'],
39
+    'sql' => "binary(16) NULL"
40
+];
0 41
new file mode 100644
... ...
@@ -0,0 +1,37 @@
1
+<?php
2
+
3
+declare(strict_types=1);
4
+
5
+/*
6
+ * This file is part of Oveleon ContaoMemberExtension Bundle.
7
+ *
8
+ * @package     contao-member-extension-bundle
9
+ * @license     MIT
10
+ * @author      Daniele Sciannimanica   <https://github.com/doishub>
11
+ * @author      Fabian Ekert            <https://github.com/eki89>
12
+ * @author      Sebastian Zoglowek      <https://github.com/zoglo>
13
+ * @copyright   Oveleon                 <https://www.oveleon.de/>
14
+ */
15
+
16
+use Contao\Config;
17
+
18
+$GLOBALS['TL_DCA']['tl_member_settings'] = [
19
+
20
+	// Config
21
+	'config' => [
22
+		'dataContainer' => 'File',
23
+		'closed' => true
24
+	],
25
+
26
+	// Palettes
27
+	'palettes' => ['default' =>'{avatar_legend},defaultAvatar;'],
28
+
29
+	// Fields
30
+	'fields' => [
31
+		'defaultAvatar' => [
32
+            'label' => &$GLOBALS['TL_LANG']['tl_member_settings']['defaultAvatar'],
33
+            'inputType' => 'fileTree',
34
+            'eval' => array('fieldType'=>'radio', 'filesOnly'=>true, 'isGallery'=>true, 'extensions'=>Config::get('validImageTypes'), 'tl_class'=>'clr')
35
+		]
36
+	]
37
+];
0 38
new file mode 100644
... ...
@@ -0,0 +1,130 @@
1
+<?php
2
+
3
+declare(strict_types=1);
4
+
5
+/*
6
+ * This file is part of Oveleon ContaoMemberExtension Bundle.
7
+ *
8
+ * @package     contao-member-extension-bundle
9
+ * @license     MIT
10
+ * @author      Daniele Sciannimanica   <https://github.com/doishub>
11
+ * @author      Fabian Ekert            <https://github.com/eki89>
12
+ * @author      Sebastian Zoglowek      <https://github.com/zoglo>
13
+ * @copyright   Oveleon                 <https://www.oveleon.de/>
14
+ */
15
+
16
+use Contao\Backend;
17
+use Contao\Controller;
18
+use Contao\System;
19
+
20
+System::loadLanguageFile('tl_member_settings');
21
+
22
+// Add palettes to tl_module
23
+$GLOBALS['TL_DCA']['tl_module']['palettes']['avatar']       = '{title_legend},name,headline,type;{source_legend},imgSize;{template_legend:hide},customTpl;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
24
+$GLOBALS['TL_DCA']['tl_module']['palettes']['deleteAvatar'] = '{title_legend},name,headline,type;{template_legend:hide},customTpl;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
25
+$GLOBALS['TL_DCA']['tl_module']['palettes']['memberList']   = '{title_legend},name,headline,type;{config_legend},ext_order,ext_orderField,numberOfItems,perPage,ext_groups,memberFields,imgSize;{redirect_legend},jumpTo;{template_legend:hide},customTpl,memberListTpl;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
26
+$GLOBALS['TL_DCA']['tl_module']['palettes']['memberReader'] = '{title_legend},name,headline,type;{config_legend},ext_groups,memberFields,imgSize;{template_legend:hide},customTpl,memberReaderTpl;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
27
+
28
+$GLOBALS['TL_DCA']['tl_module']['fields']['memberListTpl'] = [
29
+    'exclude' => true,
30
+    'inputType' => 'select',
31
+    'options_callback' => static fn () => Controller::getTemplateGroup('memberExtension_list_'),
32
+    'eval' => ['includeBlankOption'=>true, 'chosen'=>true, 'tl_class'=>'w50'],
33
+    'sql' => "varchar(64) NOT NULL default ''"
34
+];
35
+
36
+$GLOBALS['TL_DCA']['tl_module']['fields']['memberReaderTpl'] = [
37
+    'exclude' => true,
38
+    'inputType' => 'select',
39
+    'options_callback' => static fn () => Controller::getTemplateGroup('memberExtension_reader_'),
40
+    'eval' => ['includeBlankOption'=>true, 'chosen'=>true, 'tl_class'=>'w50'],
41
+    'sql' => "varchar(64) NOT NULL default ''"
42
+];
43
+
44
+$GLOBALS['TL_DCA']['tl_module']['fields']['ext_order'] = [
45
+    'exclude' => true,
46
+    'inputType' => 'select',
47
+    'options' => ['order_random', 'order_asc', 'order_desc'],
48
+    'reference' => &$GLOBALS['TL_LANG']['tl_member_settings'],
49
+    'eval' => ['tl_class'=>'w50 clr', 'includeBlankOption'=>true, 'chosen'=>true,],
50
+    'sql' => "varchar(32) NOT NULL default ''"
51
+];
52
+
53
+$GLOBALS['TL_DCA']['tl_module']['fields']['ext_orderField'] = [
54
+    'exclude' => true,
55
+    'inputType' => 'select',
56
+    'options_callback' => ['tl_module_extension', 'getViewableMemberFields'],
57
+    'eval' => ['tl_class'=>'w50', 'includeBlankOption'=>true, 'chosen'=>true,],
58
+    'sql' => "varchar(32) NOT NULL default ''"
59
+];
60
+
61
+$GLOBALS['TL_DCA']['tl_module']['fields']['memberFields'] = [
62
+    'exclude' => true,
63
+    'inputType' => 'checkboxWizard',
64
+    'options_callback' => ['tl_module_extension', 'getMemberProperties'],
65
+    'eval' => ['multiple'=>true, 'tl_class'=>'clr'],
66
+    'sql' => "blob NULL"
67
+];
68
+
69
+$GLOBALS['TL_DCA']['tl_module']['fields']['ext_groups'] = [
70
+    'exclude' => true,
71
+    'inputType' => 'checkbox',
72
+    'foreignKey' => 'tl_member_group.name',
73
+    'eval' => ['multiple'=>true, 'tl_class'=>'clr'],
74
+    'sql' => "blob NULL",
75
+    'relation' => ['type'=>'hasMany', 'load'=>'lazy']
76
+];
77
+
78
+class tl_module_extension extends Backend
79
+{
80
+    /**
81
+     * Import the back end user object
82
+     */
83
+    public function __construct()
84
+    {
85
+        parent::__construct();
86
+        $this->import('Contao\BackendUser', 'User');
87
+    }
88
+
89
+    /**
90
+     * Return all fields of table tl_member without account data
91
+     */
92
+    public function getMemberProperties(): array
93
+    {
94
+        $return = [];
95
+
96
+        Contao\System::loadLanguageFile('tl_member');
97
+        $this->loadDataContainer('tl_member');
98
+
99
+        foreach ($GLOBALS['TL_DCA']['tl_member']['fields'] as $k=>$v)
100
+        {
101
+            if (!empty($v['inputType']) && $v['inputType'] !== 'password')
102
+            {
103
+                $return[$k] = $GLOBALS['TL_DCA']['tl_member']['fields'][$k]['label'][0];
104
+            }
105
+        }
106
+
107
+        return $return;
108
+    }
109
+
110
+    /**
111
+     * Return all sortable fields of table tl_member
112
+     */
113
+    public function getViewableMemberFields(): array
114
+	{
115
+        $return = [];
116
+
117
+        Contao\System::loadLanguageFile('tl_member');
118
+        $this->loadDataContainer('tl_member');
119
+
120
+        foreach ($GLOBALS['TL_DCA']['tl_member']['fields'] as $k=>$v)
121
+        {
122
+            if (!empty($v['inputType']) && $k !== 'avatar' && isset($v['eval']['feViewable']) && $v['eval']['feViewable'] === true)
123
+            {
124
+                $return[$k] = $GLOBALS['TL_DCA']['tl_member']['fields'][$k]['label'][0] . ' ['.$k.']';
125
+            }
126
+        }
127
+
128
+        return $return;
129
+    }
130
+}
0 131
new file mode 100644
... ...
@@ -0,0 +1,22 @@
1
+<?xml version="1.0" ?><xliff version="1.1">
2
+  <file datatype="php" original="src/Resources/contao/languages/en/default.php" source-language="en" target-language="de">
3
+    <body>
4
+      <trans-unit id="MSC.emptyMemberList">
5
+        <source>No members could be found.</source>
6
+        <target>Es konnten keine Mitglieder gefunden werden.</target>
7
+      </trans-unit>
8
+      <trans-unit id="MSC.memberDetail">
9
+        <source>More</source>
10
+        <target>Mehr</target>
11
+      </trans-unit>
12
+      <trans-unit id="MSC.deleteAvatar">
13
+        <source>Delete avatar</source>
14
+        <target>Profilbild löschen</target>
15
+      </trans-unit>
16
+      <trans-unit id="MSC.avatarDeleted">
17
+        <source>The avatar was successfully deleted</source>
18
+        <target>Das Profilbild wurde erfolgreich gelöscht</target>
19
+      </trans-unit>
20
+    </body>
21
+  </file>
22
+</xliff>
0 23
new file mode 100644
... ...
@@ -0,0 +1,46 @@
1
+<?xml version="1.0" ?><xliff version="1.1">
2
+  <file datatype="php" original="src/Resources/contao/languages/en/modules.php" source-language="en" target-language="de">
3
+    <body>
4
+      <trans-unit id="MOD.member_settings.0">
5
+        <source>Member settings</source>
6
+        <target>Mitglieder-Einstellungen</target>
7
+      </trans-unit>
8
+      <trans-unit id="MOD.member_settings.1">
9
+        <source>Configure member settings</source>
10
+        <target>Mitglieder-Einstellungen vornehmen</target>
11
+      </trans-unit>
12
+      <trans-unit id="FMD.avatar.0">
13
+        <source>Profile picture / Avatar</source>
14
+        <target>Profilbild / Avatar</target>
15
+      </trans-unit>
16
+      <trans-unit id="FMD.avatar.1">
17
+        <source>Displays the profile picture of the member.</source>
18
+        <target>Zeigt das Profilbild des Mitgliedes an.</target>
19
+      </trans-unit>
20
+      <trans-unit id="FMD.deleteAvatar.0">
21
+        <source>Delete avatar</source>
22
+        <target>Profilbild löschen</target>
23
+      </trans-unit>
24
+      <trans-unit id="FMD.deleteAvatar.1">
25
+        <source>Adds a button to delete the avatar of the member.</source>
26
+        <target>Fügt eine Schaltfläche zum Löschen des Profilbildes hinzu.</target>
27
+      </trans-unit>
28
+      <trans-unit id="FMD.memberList.0">
29
+        <source>Memberlist</source>
30
+        <target>Mitgliederliste</target>
31
+      </trans-unit>
32
+      <trans-unit id="FMD.memberList.1">
33
+        <source>Displays a list of members.</source>
34
+        <target>Gibt eine Liste der Mitglieder aus.</target>
35
+      </trans-unit>
36
+      <trans-unit id="FMD.memberReader.0">
37
+        <source>Memberreader</source>
38
+        <target>Mitgliedleser</target>
39
+      </trans-unit>
40
+      <trans-unit id="FMD.memberReader.1">
41
+        <source>Displays a members details.</source>
42
+        <target>Gibt eine Details eines Mitglieds aus.</target>
43
+      </trans-unit>
44
+    </body>
45
+  </file>
46
+</xliff>
0 47
new file mode 100644
... ...
@@ -0,0 +1,22 @@
1
+<?xml version="1.0" ?><xliff version="1.1">
2
+  <file datatype="php" original="src/Resources/contao/languages/en/tl_member.php" source-language="en" target-language="de">
3
+    <body>
4
+      <trans-unit id="tl_member.avatar.0">
5
+        <source>Profile picture</source>
6
+        <target>Profilbild</target>
7
+      </trans-unit>
8
+      <trans-unit id="tl_member.avatar.1">
9
+        <source>Here you can choose a profile picture for the member.</source>
10
+        <target>Hier können Sie ein Profilbild für das Mitglied auswählen.</target>
11
+      </trans-unit>
12
+      <trans-unit id="tl_member.settings.0">
13
+        <source>Settings</source>
14
+        <target>Einstellungen</target>
15
+      </trans-unit>
16
+      <trans-unit id="tl_member.settings.1">
17
+        <source>Member settings</source>
18
+        <target>Mitglieder-Einstellungen</target>
19
+      </trans-unit>
20
+    </body>
21
+  </file>
22
+</xliff>
0 23
\ No newline at end of file
1 24
new file mode 100644
... ...
@@ -0,0 +1,30 @@
1
+<?xml version="1.0" ?><xliff version="1.1">
2
+  <file datatype="php" original="src/Resources/contao/languages/en/tl_member.php" source-language="en" target-language="de">
3
+    <body>
4
+      <trans-unit id="tl_member_settings.avatar_legend">
5
+        <source>Extended member settings</source>
6
+        <target>Erweiterte Mitgliedseinstellungen</target>
7
+      </trans-unit>
8
+      <trans-unit id="tl_member_settings.defaultAvatar.0">
9
+        <source>Default avatar</source>
10
+        <target>Standard-Profilbild</target>
11
+      </trans-unit>
12
+      <trans-unit id="tl_member_settings.defaultAvatar.1">
13
+        <source>The default avatar is displayed for members who have not uploaded their own profile picture.</source>
14
+        <target>Das Standard-Profilbild wird bei Mitgliedern angezeigt, welches kein eigenes Profilbild hochgeladen haben.</target>
15
+      </trans-unit>
16
+      <trans-unit id="tl_member_settings.order_random">
17
+        <source>Random order</source>
18
+        <target>Zufällige Reihenfolge</target>
19
+      </trans-unit>
20
+      <trans-unit id="tl_member_settings.order_asc">
21
+        <source>Ascending</source>
22
+        <target>Aufsteigend</target>
23
+      </trans-unit>
24
+      <trans-unit id="tl_member_settings.order_desc">
25
+        <source>Descending</source>
26
+        <target>Absteigend</target>
27
+      </trans-unit>
28
+    </body>
29
+  </file>
30
+</xliff>
0 31
new file mode 100644
... ...
@@ -0,0 +1,62 @@
1
+<?xml version="1.0" ?><xliff version="1.1">
2
+  <file datatype="php" original="src/Resources/contao/languages/en/tl_module.php" source-language="en" target-language="de">
3
+    <body>
4
+      <trans-unit id="tl_module.ext_order.0">
5
+        <source>Sort order</source>
6
+        <target>Sortierreihenfolge</target>
7
+      </trans-unit>
8
+      <trans-unit id="tl_module.ext_order.1">
9
+        <source>Here you can choose the sort order.</source>
10
+        <target>Hier können Sie die Sortierreihenfolge festlegen.</target>
11
+      </trans-unit>
12
+      <trans-unit id="tl_module.ext_orderField.0">
13
+        <source>Sorting field</source>
14
+        <target>Sortierfeld</target>
15
+      </trans-unit>
16
+      <trans-unit id="tl_module.ext_orderField.1">
17
+        <source>Here you can select the field to be sorted by.</source>
18
+        <target>Hier können Sie das Feld auswählen, nach dem sortiert werden soll.</target>
19
+      </trans-unit>
20
+      <trans-unit id="tl_module.ext_groups.0">
21
+        <source>Groups to show</source>
22
+        <target>Anzuzeigende Gruppen</target>
23
+      </trans-unit>
24
+      <trans-unit id="tl_module.ext_groups.1">
25
+        <source>Here you can select the member groups to be displayed.</source>
26
+        <target>Hier können Sie die Mitgliedergruppen auswählen, die angezeigt werden sollen.</target>
27
+      </trans-unit>
28
+      <trans-unit id="tl_module.memberFields.0">
29
+        <source>Member fields</source>
30
+        <target>Mitglieds-Felder</target>
31
+      </trans-unit>
32
+      <trans-unit id="tl_module.memberFields.1">
33
+        <source>Here you can select the member fields to be displayed.</source>
34
+        <target>Hier können Sie die auszugebenden Mitgliederfelder auswählen.</target>
35
+      </trans-unit>
36
+      <trans-unit id="tl_module.memberFields.0">
37
+        <source>Member fields</source>
38
+        <target>Mitglieds-Felder</target>
39
+      </trans-unit>
40
+      <trans-unit id="tl_module.memberFields.1">
41
+        <source>Here you can select the member fields to be output.</source>
42
+        <target>Hier können Sie die auszugebenden Mitgliederfelder auswählen.</target>
43
+      </trans-unit>
44
+      <trans-unit id="tl_module.memberListTpl.0">
45
+        <source>List template</source>
46
+        <target>Listen-Template</target>
47
+      </trans-unit>
48
+      <trans-unit id="tl_module.memberListTpl.1">
49
+        <source>Here you can set your own member list template.</source>
50
+        <target>Hier können Sie ein eigenes Mitglieder-Listen Template einstellen.</target>
51
+      </trans-unit>
52
+      <trans-unit id="tl_module.memberReaderTpl.0">
53
+        <source>Reader template</source>
54
+        <target>Leser-Template</target>
55
+      </trans-unit>
56
+      <trans-unit id="tl_module.memberReaderTpl.1">
57
+        <source>Here you can set your own member reader template.</source>
58
+        <target>Hier können Sie ein eigenes Mitglieds-Leser Template einstellen.</target>
59
+      </trans-unit>
60
+    </body>
61
+  </file>
62
+</xliff>
0 63
new file mode 100644
... ...
@@ -0,0 +1,18 @@
1
+<?xml version="1.0" ?><xliff version="1.1">
2
+  <file datatype="php" original="src/Resources/contao/languages/en/default.php" source-language="en">
3
+    <body>
4
+      <trans-unit id="MSC.emptyMemberList">
5
+        <source>No members could be found.</source>
6
+      </trans-unit>
7
+      <trans-unit id="MSC.memberDetail">
8
+        <source>More</source>
9
+      </trans-unit>
10
+      <trans-unit id="MSC.deleteAvatar">
11
+        <source>Delete avatar</source>
12
+      </trans-unit>
13
+      <trans-unit id="MSC.avatarDeleted">
14
+        <source>The avatar was successfully deleted</source>
15
+      </trans-unit>
16
+    </body>
17
+  </file>
18
+</xliff>
0 19
new file mode 100644
... ...
@@ -0,0 +1,36 @@
1
+<?xml version="1.0" ?><xliff version="1.1">
2
+  <file datatype="php" original="src/Resources/contao/languages/en/modules.php" source-language="en">
3
+    <body>
4
+      <trans-unit id="MOD.member_settings.0">
5
+        <source>Member settings</source>
6
+      </trans-unit>
7
+      <trans-unit id="MOD.member_settings.1">
8
+        <source>Configure member settings</source>
9
+      </trans-unit>
10
+      <trans-unit id="FMD.avatar.0">
11
+        <source>Avatar / profile picture</source>
12
+      </trans-unit>
13
+      <trans-unit id="FMD.avatar.1">
14
+        <source>Displays the avatar of the member.</source>
15
+      </trans-unit>
16
+      <trans-unit id="FMD.deleteAvatar.0">
17
+        <source>Delete avatar</source>
18
+      </trans-unit>
19
+      <trans-unit id="FMD.deleteAvatar.1">
20
+        <source>Adds a button to delete the avatar of the member.</source>
21
+      </trans-unit>
22
+      <trans-unit id="FMD.memberList.0">
23
+        <source>Memberlist</source>
24
+      </trans-unit>
25
+      <trans-unit id="FMD.memberList.1">
26
+        <source>Displays a list of members.</source>
27
+      </trans-unit>
28
+      <trans-unit id="FMD.memberReader.0">
29
+        <source>Memberreader</source>
30
+      </trans-unit>
31
+      <trans-unit id="FMD.memberReader.1">
32
+        <source>Displays a members details.</source>
33
+      </trans-unit>
34
+    </body>
35
+  </file>
36
+</xliff>
0 37
new file mode 100644
... ...
@@ -0,0 +1,18 @@
1
+<?xml version="1.0" ?><xliff version="1.1">
2
+  <file datatype="php" original="src/Resources/contao/languages/en/tl_member.php" source-language="en">
3
+    <body>
4
+      <trans-unit id="tl_member.avatar.0">
5
+        <source>Avatar</source>
6
+      </trans-unit>
7
+      <trans-unit id="tl_member.avatar.1">
8
+        <source>Here you can choose an avatar for the member.</source>
9
+      </trans-unit>
10
+      <trans-unit id="tl_member.settings.0">
11
+        <source>Settings</source>
12
+      </trans-unit>
13
+      <trans-unit id="tl_member.settings.1">
14
+        <source>Member settings</source>
15
+      </trans-unit>
16
+    </body>
17
+  </file>
18
+</xliff>
0 19
\ No newline at end of file
1 20
new file mode 100644
... ...
@@ -0,0 +1,24 @@
1
+<?xml version="1.0" ?><xliff version="1.1">
2
+  <file datatype="php" original="src/Resources/contao/languages/en/tl_member.php" source-language="en">
3
+    <body>
4
+      <trans-unit id="tl_member_settings.avatar_legend">
5
+        <source>Extended member settings</source>
6
+      </trans-unit>
7
+      <trans-unit id="tl_member_settings.defaultAvatar.0">
8
+        <source>Default avatar</source>
9
+      </trans-unit>
10
+      <trans-unit id="tl_member_settings.defaultAvatar.1">
11
+        <source>The default avatar is displayed for members who have not uploaded their own profile picture.</source>
12
+      </trans-unit>
13
+      <trans-unit id="tl_member_settings.order_random">
14
+        <source>Random order</source>
15
+      </trans-unit>
16
+      <trans-unit id="tl_member_settings.order_asc">
17
+        <source>Ascending</source>
18
+      </trans-unit>
19
+      <trans-unit id="tl_member_settings.order_desc">
20
+        <source>Descending</source>
21
+      </trans-unit>
22
+    </body>
23
+  </file>
24
+</xliff>
0 25
new file mode 100644
... ...
@@ -0,0 +1,48 @@
1
+<?xml version="1.0" ?><xliff version="1.1">
2
+  <file datatype="php" original="src/Resources/contao/languages/en/tl_module.php" source-language="en">
3
+    <body>
4
+      <trans-unit id="tl_module.ext_order.0">
5
+        <source>Sort order</source>
6
+      </trans-unit>
7
+      <trans-unit id="tl_module.ext_order.1">
8
+        <source>Here you can choose the sort order.</source>
9
+      </trans-unit>
10
+      <trans-unit id="tl_module.ext_orderField.0">
11
+        <source>Sorting field</source>
12
+      </trans-unit>
13
+      <trans-unit id="tl_module.ext_orderField.1">
14
+        <source>Here you can select the field to be sorted by.</source>
15
+      </trans-unit>
16
+      <trans-unit id="tl_module.ext_groups.0">
17
+        <source>Groups to show</source>
18
+      </trans-unit>
19
+      <trans-unit id="tl_module.ext_groups.1">
20
+        <source>Here you can select the member groups to be displayed.</source>
21
+      </trans-unit>
22
+      <trans-unit id="tl_module.memberFields.0">
23
+        <source>Member fields</source>
24
+      </trans-unit>
25
+      <trans-unit id="tl_module.memberFields.1">
26
+        <source>Here you can select the member fields to be displayed.</source>
27
+      </trans-unit>
28
+      <trans-unit id="tl_module.memberFields.0">
29
+        <source>Member fields</source>
30
+      </trans-unit>
31
+      <trans-unit id="tl_module.memberFields.1">
32
+        <source>Here you can select the member fields to be output.</source>
33
+      </trans-unit>
34
+      <trans-unit id="tl_module.memberListTpl.0">
35
+        <source>List template</source>
36
+      </trans-unit>
37
+      <trans-unit id="tl_module.memberListTpl.1">
38
+        <source>Here you can set your own member list template.</source>
39
+      </trans-unit>
40
+      <trans-unit id="tl_module.memberReaderTpl.0">
41
+        <source>Reader template</source>
42
+      </trans-unit>
43
+      <trans-unit id="tl_module.memberReaderTpl.1">
44
+        <source>Here you can set your own member reader template.</source>
45
+      </trans-unit>
46
+    </body>
47
+  </file>
48
+</xliff>
0 49
new file mode 100644
... ...
@@ -0,0 +1,88 @@
1
+<?php
2
+
3
+declare(strict_types=1);
4
+
5
+/*
6
+ * This file is part of Oveleon ContaoMemberExtension Bundle.
7
+ *
8
+ * @package     contao-member-extension-bundle
9
+ * @license     MIT
10
+ * @author      Daniele Sciannimanica   <https://github.com/doishub>
11
+ * @author      Fabian Ekert            <https://github.com/eki89>
12
+ * @author      Sebastian Zoglowek      <https://github.com/zoglo>
13
+ * @copyright   Oveleon                 <https://www.oveleon.de/>
14
+ */
15
+
16
+namespace Oveleon\ContaoMemberExtensionBundle;
17
+
18
+use Contao\BackendTemplate;
19
+use Contao\Config;
20
+use Contao\FilesModel;
21
+use Contao\FrontendUser;
22
+use Contao\MemberModel;
23
+use Contao\Module;
24
+use Contao\System;
25
+
26
+/**
27
+ * Class ModuleAvatar
28
+ *
29
+ * @author Fabian Ekert <fabian@oveleon.de>
30
+ * @author Sebastian Zoglowek <https://github.com/zoglo>
31
+ */
32
+class ModuleAvatar extends ModuleMemberExtension
33
+{
34
+    /**
35
+     * Template.
36
+     *
37
+     * @var string
38
+     */
39
+    protected $strTemplate = 'memberExtension_avatar';
40
+
41
+    /**
42
+     * Return a wildcard in the back end
43
+     *
44
+     * @return string
45
+     */
46
+    public function generate()
47
+    {
48
+        $request = System::getContainer()->get('request_stack')->getCurrentRequest();
49
+
50
+        if ($request && System::getContainer()->get('contao.routing.scope_matcher')->isBackendRequest($request))
51
+        {
52
+            $objTemplate = new BackendTemplate('be_wildcard');
53
+            $objTemplate->wildcard = '### ' . mb_strtoupper($GLOBALS['TL_LANG']['FMD']['avatar'][0], 'UTF-8') . ' ###';
54
+            $objTemplate->title = $this->headline;
55
+            $objTemplate->id = $this->id;
56
+            $objTemplate->link = $this->name;
57
+            $objTemplate->href = 'contao/main.php?do=themes&amp;table=tl_module&amp;act=edit&amp;id=' . $this->id;
58
+
59
+            return $objTemplate->parse();
60
+        }
61
+
62
+        // Return if user is not logged in
63
+        $tokenChecker = System::getContainer()->get('contao.security.token_checker');
64
+        $blnFeUserLoggedIn = $tokenChecker->hasFrontendUser();
65
+
66
+        if (!$blnFeUserLoggedIn)
67
+        {
68
+            return '';
69
+        }
70
+
71
+        $this->strTemplate = $this->customTpl ?: 'memberExtension_avatar';
72
+
73
+        return parent::generate();
74
+    }
75
+
76
+    /**
77
+     * Generate the module
78
+     */
79
+    protected function compile()
80
+    {
81
+        $objTemplate = $this->Template;
82
+
83
+        $this->import(FrontendUser::class, 'User');
84
+        $objMember = MemberModel::findByPk($this->User->id);
85
+
86
+        Member::parseMemberAvatar($objMember, $objTemplate, $this->imgSize);
87
+    }
88
+}
0 89
new file mode 100644
... ...
@@ -0,0 +1,135 @@
1
+<?php
2
+
3
+declare(strict_types=1);
4
+
5
+/*
6
+ * This file is part of Oveleon ContaoMemberExtension Bundle.
7
+ *
8
+ * @package     contao-member-extension-bundle
9
+ * @license     MIT
10
+ * @author      Daniele Sciannimanica   <https://github.com/doishub>
11
+ * @author      Fabian Ekert            <https://github.com/eki89>
12
+ * @author      Sebastian Zoglowek      <https://github.com/zoglo>
13
+ * @copyright   Oveleon                 <https://www.oveleon.de/>
14
+ */
15
+
16
+namespace Oveleon\ContaoMemberExtensionBundle;
17
+
18
+use Contao\BackendTemplate;
19
+use Contao\Config;
20
+use Contao\FrontendUser;
21
+use Contao\Input;
22
+use Contao\MemberModel;
23
+use Contao\Module;
24
+use Contao\StringUtil;
25
+use Contao\System;
26
+
27
+/**
28
+ * Class ModuleDeleteAvatar
29
+ *
30
+ * @author Sebastian Zoglowek <https://github.com/zoglo>
31
+ */
32
+class ModuleDeleteAvatar extends Module
33
+{
34
+    /**
35
+     * Template.
36
+     *
37
+     * @var string
38
+     */
39
+    protected $strTemplate = 'memberExtension_deleteAvatar';
40
+
41
+    /**
42
+     * Return a wildcard in the back end
43
+     *
44
+     * @return string
45
+     */
46
+    public function generate()
47
+    {
48
+        $container = System::getContainer();
49
+
50
+        $request = System::getContainer()->get('request_stack')->getCurrentRequest();
51
+
52
+        if ($request && System::getContainer()->get('contao.routing.scope_matcher')->isBackendRequest($request))
53
+        {
54
+            $objTemplate = new BackendTemplate('be_wildcard');
55
+            $objTemplate->wildcard = '### ' . mb_strtoupper($GLOBALS['TL_LANG']['FMD']['deleteAvatar'][0] ?? '', 'UTF-8') . ' ###';
56
+            $objTemplate->title = $this->headline;
57
+            $objTemplate->id = $this->id;
58
+            $objTemplate->link = $this->name;
59
+            $objTemplate->href = 'contao/main.php?do=themes&amp;table=tl_module&amp;act=edit&amp;id=' . $this->id;
60
+
61
+            return $objTemplate->parse();
62
+        }
63
+
64
+        // Set the item from the auto_item parameter
65
+        if (!isset($_GET['items']) && isset($_GET['auto_item']) && Config::get('useAutoItem'))
66
+        {
67
+            Input::setGet('items', Input::get('auto_item'));
68
+        }
69
+
70
+        // Return if there is no logged-in user
71
+        if (!$container->get('contao.security.token_checker')->hasFrontendUser())
72
+        {
73
+            return '';
74
+        }
75
+
76
+        $this->import(FrontendUser::class, 'User');
77
+        $objMember = MemberModel::findByPk($this->User->id);
78
+
79
+        if(null === $objMember)
80
+        {
81
+            return '';
82
+        }
83
+
84
+        // Confirmation message
85
+        $session = System::getContainer()->get('session');
86
+        $flashBag = $session->getFlashBag();
87
+
88
+        // Return if there is no flashbag message or an avatar
89
+        if (!($session->isStarted() && $flashBag->has('mod_avatar_deleted')) && !$objMember->avatar)
90
+        {
91
+            return '';
92
+        }
93
+
94
+        return parent::generate();
95
+    }
96
+
97
+    /**
98
+     * Generate the module
99
+     */
100
+    protected function compile()
101
+    {
102
+        $strFormId = 'deleteAvatar_' . $this->id;
103
+        $session = System::getContainer()->get('session');
104
+        $flashBag = $session->getFlashBag();
105
+
106
+        // Get form submit
107
+        if (Input::post('FORM_SUBMIT') == $strFormId)
108
+        {
109
+            $this->import(FrontendUser::class, 'User');
110
+            $objMember = MemberModel::findByPk($this->User->id);
111
+
112
+            // Delete avatar if it exists
113
+            if(!!$objMember->avatar)
114
+            {
115
+                Member::deleteAvatar($objMember);
116
+                // Unset avatar
117
+                $objMember->avatar = null;
118
+                $objMember->save();
119
+
120
+                // Set message for deletion feedback
121
+                $flashBag->set('mod_avatar_deleted', $GLOBALS['TL_LANG']['MSC']['avatarDeleted']);
122
+                $this->reload();
123
+            }
124
+        }
125
+
126
+        // Confirmation message
127
+        if($session->isStarted() && $flashBag->has('mod_avatar_deleted')) {
128
+            $arrMessages = $flashBag->get('mod_avatar_deleted');
129
+            $this->Template->message = $arrMessages[0];
130
+        }
131
+
132
+        $this->Template->formId = $strFormId;
133
+        $this->Template->slabel = StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['deleteAvatar']);
134
+    }
135
+}
0 136
new file mode 100644
... ...
@@ -0,0 +1,178 @@
1
+<?php
2
+
3
+declare(strict_types=1);
4
+
5
+/*
6
+ * This file is part of Oveleon ContaoMemberExtension Bundle.
7
+ *
8
+ * @package     contao-member-extension-bundle
9
+ * @license     MIT
10
+ * @author      Daniele Sciannimanica   <https://github.com/doishub>
11
+ * @author      Fabian Ekert            <https://github.com/eki89>
12
+ * @author      Sebastian Zoglowek      <https://github.com/zoglo>
13
+ * @copyright   Oveleon                 <https://www.oveleon.de/>
14
+ */
15
+
16
+namespace Oveleon\ContaoMemberExtensionBundle;
17
+
18
+use Contao\Config;
19
+use Contao\Date;
20
+use Contao\Environment;
21
+use Contao\MemberGroupModel;
22
+use Contao\MemberModel;
23
+use Contao\Module;
24
+use Contao\PageModel;
25
+use Contao\StringUtil;
26
+use Contao\System;
27
+
28
+/**
29
+ * Parent class for member modules.
30
+ *
31
+ * @author Daniele Sciannimanica <https://github.com/doishub>
32
+ */
33
+abstract class ModuleMemberExtension extends Module
34
+{
35
+    /**
36
+     * Parse member template
37
+     *
38
+     * @param $objMember
39
+     * @param $objTemplate
40
+     * @param $arrMemberFields
41
+     * @param $strImgSize
42
+     * @return string
43
+     */
44
+    protected function parseMemberTemplate($objMember, $objTemplate, $arrMemberFields, $strImgSize): string
45
+    {
46
+        System::loadLanguageFile('default');
47
+        System::loadLanguageFile('tl_member');
48
+        System::loadLanguageFile('countries');
49
+        System::loadLanguageFile('languages');
50
+
51
+        $arrFields = [];
52
+
53
+        foreach ($arrMemberFields as $field)
54
+        {
55
+            switch($field)
56
+            {
57
+                /*case 'homeDir':
58
+                case 'assignDir':
59
+                    break;*/
60
+
61
+                case 'avatar':
62
+                    Member::parseMemberAvatar($objMember, $objTemplate, $strImgSize);
63
+                    break;
64
+
65
+                default:
66
+                    if($varValue = $objMember->{$field})
67
+                    {
68
+                        if (\is_array(($arrValue = StringUtil::deserialize($varValue))))
69
+                        {
70
+                            $arrFields[$field] = implode(",", $arrValue);
71
+                        }
72
+                        else
73
+                        {
74
+                            $arrFields[$field] = $varValue;
75
+                        }
76
+                        //self::parseMemberDetails($arrFields, $field, $varValue);
77
+                    }
78
+            }
79
+        }
80
+
81
+        $objTemplate->fields = $arrFields;
82
+
83
+        if($this->jumpTo)
84
+        {
85
+            $objTemplate->link = $this->generateMemberUrl($objMember);
86
+        }
87
+
88
+        return $objTemplate->parse();
89
+    }
90
+
91
+    /**
92
+     * Generate a URL and return it as string
93
+     *
94
+     * @param MemberModel $objMember
95
+     *
96
+     * @return string
97
+     */
98
+    protected function generateMemberUrl(MemberModel $objMember): string
99
+    {
100
+        $objPage = PageModel::findPublishedById($this->jumpTo);
101
+
102
+        if (!$objPage instanceof PageModel)
103
+        {
104
+            $strLink = ampersand(Environment::get('request'));
105
+        }
106
+        else
107
+        {
108
+            $params = (Config::get('useAutoItem') ? '/' : '/items/') . ($objMember->alias ?: $objMember->id);
109
+            $strLink = ampersand($objPage->getFrontendUrl($params));
110
+        }
111
+
112
+        return $strLink;
113
+    }
114
+
115
+    protected function parseMemberDetails(&$arrFields, $field, $value)
116
+    {
117
+        $strReturn = sprintf('<span class="label">%s: </span>',$GLOBALS['TL_LANG']['tl_member'][$field][0] ?? null);
118
+
119
+        if (!\is_array(($arrValue = StringUtil::deserialize($value))))
120
+        {
121
+            switch ($field) {
122
+                case 'gender':
123
+                    $strReturn .= $GLOBALS['TL_LANG']['MSC'][$value] ?? $value;
124
+                    break;
125
+
126
+                case 'email':
127
+                    $strEmail = StringUtil::encodeEmail($value);
128
+                    $strReturn .= '<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;' . $strEmail . '" title="' . $strEmail . '">' . preg_replace('/\?.*$/', '', $strEmail) . '</a>';
129
+                    break;
130
+
131
+                case 'phone':
132
+                case 'mobile':
133
+                case 'fax':
134
+                    $strTel = preg_replace('/[^a-z\d+]/i', '', (string)$value);
135
+                    $strReturn .= '<a href="tel:' . $strTel . '" title="' . $value . '">' . $value . '</a>';
136
+                    break;
137
+
138
+                case 'website':
139
+                    $strUrl = $value;
140
+
141
+                    if (strncmp($value, 'http://', 7) !== 0 || strncmp($value, 'https://', 8) !== 0) {
142
+                        $strUrl = 'https://' . $value;
143
+                    }
144
+
145
+                    $strReturn .= '<a href="' . $strUrl . '" title="' . $value . '" target="blank noopener" rel="noreferer">' . $value . '</a>';
146
+                    break;
147
+
148
+                case 'dateOfBirth':
149
+                    $strReturn .= Date::parse(Config::get('dateFormat'), $value) ?? $value;
150
+                    break;
151
+
152
+                case 'country':
153
+                    $strReturn .= $GLOBALS['TL_LANG']['CNT'][$value] ?? $value;
154
+                    break;
155
+
156
+                case 'language':
157
+                    $strReturn .= $GLOBALS['TL_LANG']['LNG'][$value] ?? $value;
158
+                    break;
159
+
160
+                default:
161
+                    $strReturn .= $value;
162
+            }
163
+        }
164
+        else if ('groups' === $field)
165
+        {
166
+            $arrReturn = [];
167
+
168
+            foreach ($arrValue as $value)
169
+            {
170
+                $arrReturn[] = MemberGroupModel::findById($value)->name;
171
+            }
172
+
173
+            $strReturn .= implode(", ", $arrReturn);
174
+        }
175
+
176
+        $arrFields[$field] = $strReturn;
177
+    }
178
+}
0 179
new file mode 100644
... ...
@@ -0,0 +1,223 @@
1
+<?php
2
+
3
+declare(strict_types=1);
4
+
5
+/*
6
+ * This file is part of Oveleon ContaoMemberExtension Bundle.
7
+ *
8
+ * @package     contao-member-extension-bundle
9
+ * @license     MIT
10
+ * @author      Daniele Sciannimanica   <https://github.com/doishub>
11
+ * @author      Fabian Ekert            <https://github.com/eki89>
12
+ * @author      Sebastian Zoglowek      <https://github.com/zoglo>
13
+ * @copyright   Oveleon                 <https://www.oveleon.de/>
14
+ */
15
+
16
+namespace Oveleon\ContaoMemberExtensionBundle;
17
+
18
+use Contao\BackendTemplate;
19
+use Contao\Config;
20
+use Contao\CoreBundle\Exception\PageNotFoundException;
21
+use Contao\Environment;
22
+use Contao\FrontendTemplate;
23
+use Contao\Input;
24
+use Contao\MemberModel;
25
+use Contao\Model\Collection;
26
+use Contao\Pagination;
27
+use Contao\StringUtil;
28
+use Contao\System;
29
+
30
+/**
31
+ * Class ModuleMemberList
32
+ *
33
+ * @property string $ext_order order of list items
34
+ * @property string ext_orderField order field for list items
35
+ * @property string $ext_groups considered member groups
36
+ * @property string $memberFields Fields to be displayed
37
+ * @property string $memberListTpl Frontend list template
38
+ */
39
+class ModuleMemberList extends ModuleMemberExtension
40
+{
41
+
42
+    /**
43
+     * Template
44
+     * @var string
45
+     */
46
+    protected $strTemplate = 'mod_memberList';
47
+
48
+    /**
49
+     * Template
50
+     * @var string
51
+     */
52
+    protected $strMemberTemplate = 'memberExtension_list_default';
53
+
54
+    /**
55
+     * Return a wildcard in the back end
56
+     *
57
+     * @return string
58
+     */
59
+    public function generate()
60
+    {
61
+        $request = System::getContainer()->get('request_stack')->getCurrentRequest();
62
+
63
+        if ($request && System::getContainer()->get('contao.routing.scope_matcher')->isBackendRequest($request))
64
+        {
65
+            $objTemplate = new BackendTemplate('be_wildcard');
66
+            $objTemplate->wildcard = '### ' . mb_strtoupper($GLOBALS['TL_LANG']['FMD']['memberList'][0], 'UTF-8') . ' ###';
67
+            $objTemplate->title = $this->headline;
68
+            $objTemplate->id = $this->id;
69
+            $objTemplate->link = $this->name;
70
+            $objTemplate->href = 'contao/main.php?do=themes&amp;table=tl_module&amp;act=edit&amp;id=' . $this->id;
71
+
72
+            return $objTemplate->parse();
73
+        }
74
+
75
+        return parent::generate();
76
+    }
77
+
78
+    /**
79
+     * Generate the module
80
+     */
81
+    protected function compile()
82
+    {
83
+        $limit = null;
84
+        $offset = 0;
85
+
86
+        $arrGroups = StringUtil::deserialize($this->ext_groups);
87
+
88
+        if(empty($arrGroups) || !\is_array($arrGroups))
89
+        {
90
+            $this->Template->empty = $GLOBALS['TL_LANG']['MSC']['emptyMemberList'];
91
+            return;
92
+        }
93
+
94
+        $objTemplate = new FrontendTemplate($this->memberListTpl ?: $this->strMemberTemplate);
95
+
96
+        $objMembers = $this->getMembers();
97
+
98
+        $intTotal = 0;
99
+
100
+        $arrMembers = [];
101
+
102
+        if(null !== $objMembers)
103
+        {
104
+            while($objMembers->next())
105
+            {
106
+                $objMember = $objMembers->current();
107
+
108
+                if(!$this->checkMemberGroups($arrGroups, $objMember))
109
+                {
110
+                    continue;
111
+                }
112
+
113
+                $intTotal += 1;
114
+
115
+                $arrMemberFields = StringUtil::deserialize($this->memberFields, true);
116
+                $objTemplate->setData($objMember->row());
117
+
118
+                $arrMembers[] = $this->parseMemberTemplate($objMember, $objTemplate, $arrMemberFields, $this->imgSize);
119
+            }
120
+        }
121
+
122
+        $total = $intTotal - $offset;
123
+
124
+        if ($this->numberOfItems > 0)
125
+        {
126
+            $limit = $this->numberOfItems;
127
+        }
128
+
129
+        if ($this->perPage > 0 && (!isset($limit) || $this->numberOfItems > $this->perPage))
130
+        {
131
+            if (isset($limit))
132
+            {
133
+                $total = min($limit, $total);
134
+            }
135
+
136
+            $id = 'page_n' . $this->id;
137
+            $page = Input::get($id) ?? 1;
138
+
139
+            if ($page < 1 || $page > max(ceil($total/$this->perPage), 1))
140
+            {
141
+                throw new PageNotFoundException('Page not found: ' . Environment::get('uri'));
142
+            }
143
+
144
+            $limit = $this->perPage;
145
+            $offset += (max($page, 1) - 1) * $this->perPage;
146
+            $skip = 0;
147
+
148
+            if ($offset + $limit > $total + $skip)
149
+            {
150
+                $limit = $total + $skip - $offset;
151
+            }
152
+
153
+            $arrMembers = \array_slice($arrMembers, $offset, ((int) $limit ?: $intTotal), true);
154
+
155
+            $objPagination = new Pagination($total, $this->perPage, Config::get('maxPaginationLinks'), $id);
156
+            $this->Template->pagination = $objPagination->generate("\n  ");
157
+        }
158
+
159
+        if(empty($arrMembers))
160
+        {
161
+            $this->Template->empty = $GLOBALS['TL_LANG']['MSC']['emptyMemberList'];
162
+        }
163
+
164
+        $this->Template->members = $arrMembers;
165
+    }
166
+
167
+    /**
168
+     * Checks whether a member is in any given group
169
+     *
170
+     * @param array $arrGroups
171
+     * @param MemberModel $objMember
172
+     * @return bool
173
+     */
174
+    private function checkMemberGroups(array $arrGroups, MemberModel $objMember): bool
175
+    {
176
+        if(empty($arrGroups))
177
+        {
178
+            return false;
179
+        }
180
+
181
+        $arrMemberGroups = StringUtil::deserialize($objMember->groups);
182
+
183
+        if(!\is_array($arrMemberGroups) || !\count(array_intersect($arrGroups, $arrMemberGroups)))
184
+        {
185
+            return false;
186
+        }
187
+
188
+        return true;
189
+    }
190
+
191
+    /**
192
+     * Get members
193
+     *
194
+     * @return Collection|MemberModel|null
195
+     */
196
+    private function getMembers()
197
+    {
198
+        $t = MemberModel::getTable();
199
+        $arrOptions = ['order' => ''];
200
+
201
+        if (!!$this->ext_orderField)
202
+        {
203
+            $arrOptions['order'] .= "$t.$this->ext_orderField ";
204
+        }
205
+
206
+        switch ($this->ext_order)
207
+        {
208
+            case 'order_random':
209
+                $arrOptions['order'] = "RAND()";
210
+                break;
211
+
212
+            case 'order_desc':
213
+                $arrOptions['order'] .= "DESC";
214
+                break;
215
+
216
+            case 'order_asc':
217
+            default:
218
+                break;
219
+        }
220
+
221
+        return MemberModel::findBy(["$t.disable=''"], null, $arrOptions);
222
+    }
223
+}
0 224
new file mode 100644
... ...
@@ -0,0 +1,113 @@
1
+<?php
2
+
3
+declare(strict_types=1);
4
+
5
+/*
6
+ * This file is part of Oveleon ContaoMemberExtension Bundle.
7
+ *
8
+ * @package     contao-member-extension-bundle
9
+ * @license     MIT
10
+ * @author      Daniele Sciannimanica   <https://github.com/doishub>
11
+ * @author      Fabian Ekert            <https://github.com/eki89>
12
+ * @author      Sebastian Zoglowek      <https://github.com/zoglo>
13
+ * @copyright   Oveleon                 <https://www.oveleon.de/>
14
+ */
15
+
16
+namespace Oveleon\ContaoMemberExtensionBundle;
17
+
18
+use Contao\BackendTemplate;
19
+use Contao\Config;
20
+use Contao\CoreBundle\Exception\PageNotFoundException;
21
+use Contao\Environment;
22
+use Contao\FrontendTemplate;
23
+use Contao\Input;
24
+use Contao\MemberModel;
25
+use Contao\StringUtil;
26
+use Contao\System;
27
+
28
+/**
29
+ * Class ModuleMemberList
30
+ * 
31
+ * @property string $ext_groups considered member groups
32
+ * @property string $memberFields Fields to be displayed
33
+ * @property string $memberReaderTpl Frontend reader template
34
+ */
35
+class ModuleMemberReader extends ModuleMemberExtension
36
+{
37
+
38
+	/**
39
+	 * Template
40
+	 * @var string
41
+	 */
42
+	protected $strTemplate = 'mod_memberReader';
43
+
44
+	/**
45
+	 * Template
46
+	 * @var string
47
+	 */
48
+	protected $strMemberTemplate = 'memberExtension_reader_full';
49
+
50
+	/**
51
+	 * Return a wildcard in the back end
52
+	 *
53
+	 * @return string
54
+	 */
55
+	public function generate()
56
+	{
57
+        $request = System::getContainer()->get('request_stack')->getCurrentRequest();
58
+
59
+        if ($request && System::getContainer()->get('contao.routing.scope_matcher')->isBackendRequest($request))
60
+        {
61
+            $objTemplate = new BackendTemplate('be_wildcard');
62
+			$objTemplate->wildcard = '### ' . mb_strtoupper($GLOBALS['TL_LANG']['FMD']['memberList'][0], 'UTF-8') . ' ###';
63
+			$objTemplate->title = $this->headline;
64
+			$objTemplate->id = $this->id;
65
+			$objTemplate->link = $this->name;
66
+			$objTemplate->href = 'contao/main.php?do=themes&amp;table=tl_module&amp;act=edit&amp;id=' . $this->id;
67
+
68
+			return $objTemplate->parse();
69
+		}
70
+
71
+        // Set the item from the auto_item parameter
72
+        if (!isset($_GET['items']) && isset($_GET['auto_item']) && Config::get('useAutoItem'))
73
+        {
74
+            Input::setGet('items', Input::get('auto_item'));
75
+        }
76
+
77
+		return parent::generate();
78
+	}
79
+
80
+	/**
81
+	 * Generate the module
82
+	 */
83
+	protected function compile()
84
+	{
85
+        $this->Template->referer = 'javascript:history.go(-1)';
86
+        $this->Template->back = $GLOBALS['TL_LANG']['MSC']['goBack'];
87
+
88
+        // Get the member
89
+        $objMember = MemberModel::findByIdOrAlias(Input::get('items'));
90
+
91
+        // The member does not exist and is not deactivated
92
+        if ($objMember === null || $objMember->disable)
93
+        {
94
+            throw new PageNotFoundException('Page not found: ' . Environment::get('uri'));
95
+        }
96
+
97
+        // Check for group intersection
98
+        $arrGroups = StringUtil::deserialize($this->ext_groups);
99
+        $memberGroups = StringUtil::deserialize($objMember->groups);
100
+
101
+        if (empty($arrGroups) || !\is_array($arrGroups) || !\count(array_intersect($arrGroups, $memberGroups)))
102
+        {
103
+            throw new PageNotFoundException('Page not found: ' . Environment::get('uri'));
104
+        }
105
+
106
+        $arrMemberFields = StringUtil::deserialize($this->memberFields, true);
107
+
108
+        $objTemplate = new FrontendTemplate($this->memberReaderTpl ?: $this->strMemberTemplate);
109
+        $objTemplate->setData($objMember->row());
110
+
111
+        $this->Template->member = $this->parseMemberTemplate($objMember, $objTemplate, $arrMemberFields, $this->imgSize);
112
+	}
113
+}
0 114
new file mode 100644
... ...
@@ -0,0 +1,8 @@
1
+<figure class="image_container">
2
+
3
+  <?php if($this->addFallbackImage): ?>
4
+    <img src="<?= $this->singleSRC; ?>" width="200" height="200" itemprop="image">
5
+  <?php else: ?>
6
+    <?php $this->insert('picture_default', $this->picture); ?>
7
+  <?php endif; ?>
8
+</figure>
0 9
new file mode 100644
... ...
@@ -0,0 +1,7 @@
1
+<?php $this->extend('block_searchable'); ?>
2
+
3
+<?php $this->block('content'); ?>
4
+
5
+<?php $this->insert('memberExtension_image', $this->arrData); ?>
6
+
7
+<?php $this->endblock(); ?>
0 8
new file mode 100644
... ...
@@ -0,0 +1,23 @@
1
+<?php $this->extend('block_unsearchable'); ?>
2
+
3
+<?php $this->block('content'); ?>
4
+
5
+<!-- indexer::stop -->
6
+
7
+  <?php if ($this->message): ?>
8
+    <p class="tl_confirm"><?= $this->message ?></p>
9
+  <?php else: ?>
10
+    <form id="<?= $this->formId ?>" method="post">
11
+      <div class="formbody">
12
+        <input type="hidden" name="FORM_SUBMIT" value="<?= $this->formId ?>">
13
+        <input type="hidden" name="REQUEST_TOKEN" value="{{request_token}}">
14
+        <div class="widget widget-submit">
15
+          <button type="submit" class="submit"><?= $this->slabel ?></button>
16
+        </div>
17
+      </div>
18
+    </form>
19
+  <?php endif; ?>
20
+
21
+<!-- indexer::continue -->
22
+
23
+<?php $this->endblock(); ?>
0 24
new file mode 100644
... ...
@@ -0,0 +1,16 @@
1
+<div class="member_list_default">
2
+
3
+  <?php if($this->addImage): ?>
4
+    <?php $this->insert('memberExtension_image', $this->arrData); ?>
5
+  <?php endif; ?>
6
+
7
+  <ul>
8
+    <?php foreach ($this->fields as $k => $v): ?>
9
+      <li class="<?= $k ?>"><?= $v ?></li>
10
+    <?php endforeach; ?>
11
+  </ul>
12
+
13
+  <?php if($this->link): ?>
14
+    <a href="<?=$this->link?>"><?=$GLOBALS['TL_LANG']['MSC']['memberDetail']?></a>
15
+  <?php endif; ?>
16
+</div>
0 17
new file mode 100644
... ...
@@ -0,0 +1,12 @@
1
+<div class="member_reader_full">
2
+
3
+  <?php if($this->addImage): ?>
4
+    <?php $this->insert('memberExtension_image', $this->arrData); ?>
5
+  <?php endif; ?>
6
+
7
+  <ul>
8
+    <?php foreach ($this->fields as $k => $v): ?>
9
+      <li class="<?= $k ?>"><?= $v ?></li>
10
+    <?php endforeach; ?>
11
+  </ul>
12
+</div>
0 13
new file mode 100644
... ...
@@ -0,0 +1,14 @@
1
+<?php $this->extend('block_unsearchable'); ?>
2
+
3
+<?php $this->block('content'); ?>
4
+
5
+<?php if (empty($this->members)): ?>
6
+    <p class="empty message"><?=$this->empty?></p>
7
+<?php else: ?>
8
+    <?php foreach ($this->members as $member): ?>
9
+      <?=$member?>
10
+    <?php endforeach; ?>
11
+    <?= $this->pagination ?>
12
+<?php endif; ?>
13
+
14
+<?php $this->endblock(); ?>
0 15
new file mode 100644
... ...
@@ -0,0 +1,11 @@
1
+<?php $this->extend('block_unsearchable'); ?>
2
+
3
+<?php $this->block('content'); ?>
4
+
5
+<?=$this->member?>
6
+
7
+<!-- indexer::stop -->
8
+<p class="back"><a href="<?= $this->referer ?>" title="<?= $this->back ?>"><?= $this->back ?></a></p>
9
+<!-- indexer::continue -->
10
+
11
+<?php $this->endblock(); ?>
0 12
new file mode 100644
1 13
Binary files /dev/null and b/public/avatar.png differ
... ...
@@ -19,4 +19,8 @@ use Symfony\Component\HttpKernel\Bundle\Bundle;
19 19
 
20 20
 class ContaoMemberExtensionBundle extends Bundle
21 21
 {
22
-}
23 22
\ No newline at end of file
23
+    public function getPath(): string
24
+    {
25
+        return \dirname(__DIR__);
26
+    }
27
+}
... ...
@@ -21,7 +21,7 @@ class ContaoMemberExtensionExtension extends Extension
21 21
     {
22 22
         $loader = new YamlFileLoader(
23 23
             $container,
24
-            new FileLocator(__DIR__.'/../Resources/config')
24
+            new FileLocator(__DIR__.'/../../config')
25 25
         );
26 26
 
27 27
         $loader->load('listener.yml');
28 28
deleted file mode 100644
... ...
@@ -1,8 +0,0 @@
1
-services:
2
-    contao_member.listener.insert_tags:
3
-        class: Oveleon\ContaoMemberExtensionBundle\EventListener\InsertTagsListener
4
-        arguments:
5
-            - '@contao.framework'
6
-        tags:
7
-          - { name: contao.hook, hook: replaceInsertTags }
8
-        public: true
9 0
deleted file mode 100644
... ...
@@ -1,323 +0,0 @@
1
-<?php
2
-
3
-declare(strict_types=1);
4
-
5
-/*
6
- * This file is part of Oveleon ContaoMemberExtension Bundle.
7
- *
8
- * @package     contao-member-extension-bundle
9
- * @license     MIT
10
- * @author      Daniele Sciannimanica   <https://github.com/doishub>
11
- * @author      Fabian Ekert            <https://github.com/eki89>
12
- * @author      Sebastian Zoglowek      <https://github.com/zoglo>
13
- * @copyright   Oveleon                 <https://www.oveleon.de/>
14
- */
15
-
16
-namespace Oveleon\ContaoMemberExtensionBundle;
17
-
18
-use Contao\Config;
19
-use Contao\CoreBundle\Monolog\ContaoContext;
20
-use Contao\Dbafs;
21
-use Contao\File;
22
-use Contao\FilesModel;
23
-use Contao\FileUpload;
24
-use Contao\Frontend;
25
-use Contao\FrontendUser;
26
-use Contao\MemberModel;
27
-use Contao\StringUtil;
28
-use Contao\System;
29
-use Contao\Validator;
30
-use Psr\Log\LogLevel;
31
-
32
-
33
-/**
34
- * Class Member
35
- *
36
- * @property int $avatar UUID of the avatar
37
- */
38
-class Member extends Frontend
39
-{
40
-    const DEFAULT_PICTURE = 'bundles/contaomemberextension/avatar.png';
41
-
42
-    /**
43
-     * MemberAvatar file name
44
-     */
45
-    protected string $avatarName = 'memberAvatar';
46
-
47
-    /**
48
-     * Create avatar for a member | Registration
49
-     */
50
-    public function createAvatar(int $userId, array $arrData): void
51
-    {
52
-        $objMember = MemberModel::findById($userId);
53
-        $this->processAvatar($objMember, $arrData);
54
-    }
55
-
56
-    /**
57
-     * Update avatar of a member | Login
58
-     */
59
-    public function updateAvatar(FrontendUser $objUser, array $arrData): void
60
-    {
61
-        $objMember = MemberModel::findById($objUser->id);
62
-        $this->processAvatar($objMember, $arrData);
63
-    }
64
-
65
-    /**
66
-     * Process avatar upload for a member
67
-     */
68
-    protected function processAvatar(MemberModel $objMember, ?array $arrData): void
69
-    {
70
-        $objMember = MemberModel::findByPk($objMember->id);
71
-
72
-        if ($objMember === null)
73
-        {
74
-            return;
75
-        }
76
-
77
-        $file = $_SESSION['FILES']['avatar'];
78
-        $maxlength_kb = $this->getMaximumUploadSize();
79
-        $maxlength_kb_readable = $this->getReadableSize($maxlength_kb);
80
-
81
-        // Sanitize the filename
82
-        try
83
-        {
84
-            $file['name'] = StringUtil::sanitizeFileName($file['name']);
85
-        }
86
-        catch (\InvalidArgumentException $e)
87
-        {
88
-            // ToDo: add error message for invalid characters
89
-            return;
90
-        }
91
-
92
-        // Invalid file name
93
-        if (!Validator::isValidFileName($file['name']))
94
-        {
95
-            // ToDo: add error message for invalid characters
96
-            return;
97
-        }
98
-
99
-        // File was not uploaded
100
-        if (!is_uploaded_file($file['tmp_name']))
101
-        {
102
-            // ToDo: Add error messages
103
-            /*if ($file['error'] == 1 || $file['error'] == 2) { // Add error message for maximum file size }
104
-            elseif ($file['error'] == 3) { // Add error message for partial upload }
105
-            elseif ($file['error'] > 0) { // Add error message for failed upload }*/
106
-
107
-            unset($_SESSION['FILES']['avatar']);
108
-
109
-            return;
110
-        }
111
-
112
-        // File is too big
113
-        if ($file['size'] > $maxlength_kb)
114
-        {
115
-            // ToDo: add error message for maximum file size
116
-            unset($_SESSION['FILES']['avatar']);
117
-
118
-            return;
119
-        }
120
-
121
-        $objFile = new File($file['name']);
122
-        $uploadTypes = StringUtil::trimsplit(',', \Config::get('validImageTypes'));
123
-
124
-        // File type is not allowed
125
-        if (!\in_array($objFile->extension, $uploadTypes))
126
-        {
127
-            // ToDo: add error message for not allowed file type
128
-            unset($_SESSION['FILES']['avatar']);
129
-
130
-            return;
131
-        }
132
-
133
-        if ($arrImageSize = @getimagesize($file['tmp_name']))
134
-        {
135
-            $intImageWidth = Config::get('imageWidth');
136
-
137
-            // Image exceeds maximum image width
138
-            if ($intImageWidth > 0 && $arrImageSize[0] > $intImageWidth) {
139
-                // ToDo: add error message for exceeding width
140
-                unset($_SESSION['FILES']['avatar']);
141
-
142
-                return;
143
-            }
144
-
145
-            $intImageHeight = Config::get('imageHeight');
146
-
147
-            // Image exceeds maximum image height
148
-            if ($intImageHeight > 0 && $arrImageSize[1] > $intImageHeight) {
149
-                // ToDo: add error message for exceeding height
150
-                unset($_SESSION['FILES']['avatar']);
151
-
152
-                return;
153
-            }
154
-        }
155
-
156
-        // Upload valid file type with no width and height -> svg
157
-
158
-        // Don't upload if no homedir is assigned
159
-        // ToDo: Create homedir?
160
-        if (!$objMember->assignDir || !$objMember->homeDir)
161
-        {
162
-            // ToDo: add error message for no homedir
163
-            return;
164
-        }
165
-
166
-        $intUploadFolder = $objMember->homeDir;
167
-
168
-        $objUploadFolder = FilesModel::findByUuid($intUploadFolder);
169
-
170
-        // The upload folder could not be found
171
-        if ($objUploadFolder === null)
172
-        {
173
-            throw new Exception("Invalid upload folder ID $intUploadFolder");
174
-        }
175
-
176
-        $strUploadFolder = $objUploadFolder->path;
177
-
178
-        // Store the file if the upload folder exists
179
-        $projectDir = System::getContainer()->getParameter('kernel.project_dir');
180
-
181
-        if (!!$strUploadFolder & is_dir($projectDir . '/' . $strUploadFolder))
182
-        {
183
-            // Delete existing avatar if it exists
184
-            $this->deleteAvatar($objMember);
185
-
186
-            $this->import('Files');
187
-
188
-            // Rename file
189
-            $file['name'] =  $this->avatarName . '.' . $objFile->extension;
190
-
191
-            // Move the file to its destination
192
-            $this->Files->move_uploaded_file($file['tmp_name'], $strUploadFolder . '/' . $file['name']);
193
-            $this->Files->chmod($strUploadFolder . '/' . $file['name'], 0666 & ~umask());
194
-
195
-            $strUuid = null;
196
-            $strFile = $strUploadFolder . '/' . $file['name'];
197
-
198
-
199
-            // Generate the DB entries
200
-            if (Dbafs::shouldBeSynchronized($strFile))
201
-            {
202
-                $objModel = FilesModel::findByPath($strFile);
203
-
204
-                if ($objModel === null)
205
-                {
206
-                    $objModel = Dbafs::addResource($strFile);
207
-                }
208
-
209
-                $strUuid = StringUtil::binToUuid($objModel->uuid);
210
-
211
-                // Update the hash of the target folder
212
-                Dbafs::updateFolderHashes($strUploadFolder);
213
-
214
-                // Update member avatar
215
-                $objMember->avatar = $objModel->uuid;
216
-                $objMember->save();
217
-            }
218
-
219
-            // Add the session entry
220
-            $_SESSION['FILES']['avatar'] = array
221
-            (
222
-                'name'     => $file['name'],
223
-                'type'     => $file['type'],
224
-                'tmp_name' => $projectDir . '/' . $strFile,
225
-                'error'    => $file['error'],
226
-                'size'     => $file['size'],
227
-                'uploaded' => true,
228
-                'uuid'     => $strUuid
229
-            );
230
-
231
-            // Add a log entry
232
-            $logger = System::getContainer()->get('monolog.logger.contao');
233
-            $logger->log(LogLevel::INFO, 'File "' . $strUploadFolder . '/' . $file['name'] . '" has been uploaded', ['contao' => new ContaoContext(__METHOD__, TL_FILES)]);
234
-        }
235
-
236
-        unset($_SESSION['FILES']['avatar']);
237
-    }
238
-
239
-    /**
240
-     * Return the maximum upload file size in bytes
241
-     */
242
-    protected function getMaximumUploadSize(): string
243
-    {
244
-        if ($this->maxlength > 0)
245
-        {
246
-            return $this->maxlength;
247
-        }
248
-
249
-        return FileUpload::getMaxUploadSize();
250
-    }
251
-
252
-    /**
253
-     * Parses an avatar to the template
254
-     */
255
-    public static function parseMemberAvatar(?MemberModel $objMember, &$objTemplate, $strImgSize): void
256
-    {
257
-        $objTemplate->addImage= true;
258
-
259
-        $objTemplate->singleSRC = self::DEFAULT_PICTURE;
260
-        $objTemplate->addFallbackImage = true;
261
-
262
-        $projectDir = System::getContainer()->getParameter('kernel.project_dir');
263
-
264
-        // Check if member avatar exists
265
-        if(null === $objMember || null === $objMember->avatar || null === ($objFile = FilesModel::findByUuid($objMember->avatar)) || !\is_file($projectDir.'/'.$objFile->path))
266
-        {
267
-            $objFile = !!($uuidDefault = Config::get('defaultAvatar')) ? FilesModel::findByUuid($uuidDefault) : null;
268
-        }
269
-
270
-        // Check if config avatar exists
271
-        if (null === $objFile || !\is_file($projectDir . '/' . $objFile->path))
272
-        {
273
-            return;
274
-        }
275
-
276
-        $objTemplate->addFallbackImage = false;
277
-        $arrData = ['singleSRC'=>$objFile->path, 'size'=>$strImgSize];
278
-
279
-        //ToDo: Change to FigureBuilder in the future
280
-        $objTemplate->addImageToTemplate($objTemplate, $arrData, null, null, $objFile);
281
-    }
282
-
283
-    /**
284
-     * Gets the url for a member avatar
285
-     */
286
-    public static function getMemberAvatarURL(?MemberModel $objMember): string
287
-    {
288
-        // ToDo: Merge logic with parseMemberAvatar
289
-        $projectDir = System::getContainer()->getParameter('kernel.project_dir');
290
-
291
-        if(null === $objMember || null === $objMember->avatar || null === ($objFile = FilesModel::findByUuid($objMember->avatar)) || !\is_file($projectDir.'/'. $objFile->path))
292
-        {
293
-            $objFile = !!($uuidDefault = Config::get('defaultAvatar')) ? FilesModel::findByUuid($uuidDefault) : null;
294
-        }
295
-
296
-        // Check if config avatar exists
297
-        if (null === $objFile || !\is_file($projectDir . '/' . $objFile->path))
298
-        {
299
-            return self::DEFAULT_PICTURE;
300
-        }
301
-
302
-        return $objFile->path;
303
-    }
304
-
305
-    /**
306
-     * Deletes an avatar
307
-     */
308
-    public static function deleteAvatar(MemberModel $objMember): void
309
-    {
310
-        if(!!$objMember->avatar)
311
-        {
312
-            $objFile = FilesModel::findByUuid($objMember->avatar) ?: '';
313
-            $projectDir = System::getContainer()->getParameter('kernel.project_dir');
314
-
315
-            // Only delete if file exists
316
-            if (!!$objFile && file_exists($projectDir . '/' . $objFile->path))
317
-            {
318
-                $file = new File($objFile->path);
319
-                $file->delete();
320
-            }
321
-        }
322
-    }
323
-}
324 0
deleted file mode 100644
... ...
@@ -1,38 +0,0 @@
1
-<?php
2
-
3
-declare(strict_types=1);
4
-
5
-/*
6
- * This file is part of Oveleon ContaoMemberExtension Bundle.
7
- *
8
- * @package     contao-member-extension-bundle
9
- * @license     MIT
10
- * @author      Daniele Sciannimanica   <https://github.com/doishub>
11
- * @author      Fabian Ekert            <https://github.com/eki89>
12
- * @author      Sebastian Zoglowek      <https://github.com/zoglo>
13
- * @copyright   Oveleon                 <https://www.oveleon.de/>
14
- */
15
-
16
-// Back end modules
17
-use Contao\System;
18
-
19
-$GLOBALS['BE_MOD']['system']['member_settings'] = [
20
-    'tables'            => ['tl_member_settings'],
21
-    'hideInNavigation'  => true,
22
-];
23
-
24
-// Front end modules
25
-// ToDo: Change to ArrayUtil::arrayInsert when Contao 4.9 support ends
26
-array_insert($GLOBALS['FE_MOD']['user'], -1, [
27
-    'avatar'       => 'Oveleon\ContaoMemberExtensionBundle\ModuleAvatar',
28
-    'deleteAvatar' => 'Oveleon\ContaoMemberExtensionBundle\ModuleDeleteAvatar',
29
-    'memberList'   => 'Oveleon\ContaoMemberExtensionBundle\ModuleMemberList',
30
-    'memberReader' => 'Oveleon\ContaoMemberExtensionBundle\ModuleMemberReader'
31
-]);
32
-
33
-// Register hooks
34
-$GLOBALS['TL_HOOKS']['createNewUser'][] = ['Oveleon\ContaoMemberExtensionBundle\Member', 'createAvatar'];
35
-$GLOBALS['TL_HOOKS']['updatePersonalData'][] = ['Oveleon\ContaoMemberExtensionBundle\Member', 'updateAvatar'];
36
-
37
-// Style sheet
38
-$request = System::getContainer()->get('request_stack')->getCurrentRequest();
39 0
deleted file mode 100644
... ...
@@ -1,40 +0,0 @@
1
-<?php
2
-
3
-declare(strict_types=1);
4
-
5
-/*
6
- * This file is part of Oveleon ContaoMemberExtension Bundle.
7
- *
8
- * @package     contao-member-extension-bundle
9
- * @license     MIT
10
- * @author      Daniele Sciannimanica   <https://github.com/doishub>
11
- * @author      Fabian Ekert            <https://github.com/eki89>
12
- * @author      Sebastian Zoglowek      <https://github.com/zoglo>
13
- * @copyright   Oveleon                 <https://www.oveleon.de/>
14
- */
15
-
16
-use Contao\Config;
17
-use Contao\CoreBundle\DataContainer\PaletteManipulator;
18
-
19
-// Extend the default palette
20
-PaletteManipulator::create()
21
-    ->addField(['avatar'], 'personal_legend', PaletteManipulator::POSITION_APPEND)
22
-    ->applyToPalette('default', 'tl_member')
23
-;
24
-
25
-// Add global operations
26
-$GLOBALS['TL_DCA']['tl_member']['list']['global_operations']['settings'] = [
27
-    'label' => &$GLOBALS['TL_LANG']['tl_member']['settings'],
28
-    'href' => 'do=member_settings',
29
-    'icon' => 'edit.svg',
30
-    'attributes' => 'onclick="Backend.getScrollOffset()" accesskey="e"'
31
-];
32
-
33
-// Add fields to tl_user
34
-$GLOBALS['TL_DCA']['tl_member']['fields']['avatar'] = [
35
-    'label' => &$GLOBALS['TL_LANG']['tl_member']['avatar'],
36
-    'exclude' => true,
37
-    'inputType' => 'fileTree',
38
-    'eval' => ['feEditable'=>true, 'feViewable'=>true, 'feGroup'=>'personal', 'fieldType'=>'radio', 'filesOnly'=>true, 'isGallery'=>true, 'extensions'=>Config::get('validImageTypes'), 'tl_class'=>'clr'],
39
-    'sql' => "binary(16) NULL"
40
-];
41 0
deleted file mode 100644
... ...
@@ -1,37 +0,0 @@
1
-<?php
2
-
3
-declare(strict_types=1);
4
-
5
-/*
6
- * This file is part of Oveleon ContaoMemberExtension Bundle.
7
- *
8
- * @package     contao-member-extension-bundle
9
- * @license     MIT
10
- * @author      Daniele Sciannimanica   <https://github.com/doishub>
11
- * @author      Fabian Ekert            <https://github.com/eki89>
12
- * @author      Sebastian Zoglowek      <https://github.com/zoglo>
13
- * @copyright   Oveleon                 <https://www.oveleon.de/>
14
- */
15
-
16
-use Contao\Config;
17
-
18
-$GLOBALS['TL_DCA']['tl_member_settings'] = [
19
-
20
-	// Config
21
-	'config' => [
22
-		'dataContainer' => 'File',
23
-		'closed' => true
24
-	],
25
-
26
-	// Palettes
27
-	'palettes' => ['default' =>'{avatar_legend},defaultAvatar;'],
28
-
29
-	// Fields
30
-	'fields' => [
31
-		'defaultAvatar' => [
32
-            'label' => &$GLOBALS['TL_LANG']['tl_member_settings']['defaultAvatar'],
33
-            'inputType' => 'fileTree',
34
-            'eval' => array('fieldType'=>'radio', 'filesOnly'=>true, 'isGallery'=>true, 'extensions'=>Config::get('validImageTypes'), 'tl_class'=>'clr')
35
-		]
36
-	]
37
-];
38 0
deleted file mode 100644
... ...
@@ -1,130 +0,0 @@
1
-<?php
2
-
3
-declare(strict_types=1);
4
-
5
-/*
6
- * This file is part of Oveleon ContaoMemberExtension Bundle.
7
- *
8
- * @package     contao-member-extension-bundle
9
- * @license     MIT
10
- * @author      Daniele Sciannimanica   <https://github.com/doishub>
11
- * @author      Fabian Ekert            <https://github.com/eki89>
12
- * @author      Sebastian Zoglowek      <https://github.com/zoglo>
13
- * @copyright   Oveleon                 <https://www.oveleon.de/>
14
- */
15
-
16
-use Contao\Backend;
17
-use Contao\Controller;
18
-use Contao\System;
19
-
20
-System::loadLanguageFile('tl_member_settings');
21
-
22
-// Add palettes to tl_module
23
-$GLOBALS['TL_DCA']['tl_module']['palettes']['avatar']       = '{title_legend},name,headline,type;{source_legend},imgSize;{template_legend:hide},customTpl;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
24
-$GLOBALS['TL_DCA']['tl_module']['palettes']['deleteAvatar'] = '{title_legend},name,headline,type;{template_legend:hide},customTpl;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
25
-$GLOBALS['TL_DCA']['tl_module']['palettes']['memberList']   = '{title_legend},name,headline,type;{config_legend},ext_order,ext_orderField,numberOfItems,perPage,ext_groups,memberFields,imgSize;{redirect_legend},jumpTo;{template_legend:hide},customTpl,memberListTpl;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
26
-$GLOBALS['TL_DCA']['tl_module']['palettes']['memberReader'] = '{title_legend},name,headline,type;{config_legend},ext_groups,memberFields,imgSize;{template_legend:hide},customTpl,memberReaderTpl;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
27
-
28
-$GLOBALS['TL_DCA']['tl_module']['fields']['memberListTpl'] = [
29
-    'exclude' => true,
30
-    'inputType' => 'select',
31
-    'options_callback' => static fn () => Controller::getTemplateGroup('memberExtension_list_'),
32
-    'eval' => ['includeBlankOption'=>true, 'chosen'=>true, 'tl_class'=>'w50'],
33
-    'sql' => "varchar(64) NOT NULL default ''"
34
-];
35
-
36
-$GLOBALS['TL_DCA']['tl_module']['fields']['memberReaderTpl'] = [
37
-    'exclude' => true,
38
-    'inputType' => 'select',
39
-    'options_callback' => static fn () => Controller::getTemplateGroup('memberExtension_reader_'),
40
-    'eval' => ['includeBlankOption'=>true, 'chosen'=>true, 'tl_class'=>'w50'],
41
-    'sql' => "varchar(64) NOT NULL default ''"
42
-];
43
-
44
-$GLOBALS['TL_DCA']['tl_module']['fields']['ext_order'] = [
45
-    'exclude' => true,
46
-    'inputType' => 'select',
47
-    'options' => ['order_random', 'order_asc', 'order_desc'],
48
-    'reference' => &$GLOBALS['TL_LANG']['tl_member_settings'],
49
-    'eval' => ['tl_class'=>'w50 clr', 'includeBlankOption'=>true, 'chosen'=>true,],
50
-    'sql' => "varchar(32) NOT NULL default ''"
51
-];
52
-
53
-$GLOBALS['TL_DCA']['tl_module']['fields']['ext_orderField'] = [
54
-    'exclude' => true,
55
-    'inputType' => 'select',
56
-    'options_callback' => ['tl_module_extension', 'getViewableMemberFields'],
57
-    'eval' => ['tl_class'=>'w50', 'includeBlankOption'=>true, 'chosen'=>true,],
58
-    'sql' => "varchar(32) NOT NULL default ''"
59
-];
60
-
61
-$GLOBALS['TL_DCA']['tl_module']['fields']['memberFields'] = [
62
-    'exclude' => true,
63
-    'inputType' => 'checkboxWizard',
64
-    'options_callback' => ['tl_module_extension', 'getMemberProperties'],
65
-    'eval' => ['multiple'=>true, 'tl_class'=>'clr'],
66
-    'sql' => "blob NULL"
67
-];
68
-
69
-$GLOBALS['TL_DCA']['tl_module']['fields']['ext_groups'] = [
70
-    'exclude' => true,
71
-    'inputType' => 'checkbox',
72
-    'foreignKey' => 'tl_member_group.name',
73
-    'eval' => ['multiple'=>true, 'tl_class'=>'clr'],
74
-    'sql' => "blob NULL",
75
-    'relation' => ['type'=>'hasMany', 'load'=>'lazy']
76
-];
77
-
78
-class tl_module_extension extends Backend
79
-{
80
-    /**
81
-     * Import the back end user object
82
-     */
83
-    public function __construct()
84
-    {
85
-        parent::__construct();
86
-        $this->import('Contao\BackendUser', 'User');
87
-    }
88
-
89
-    /**
90
-     * Return all fields of table tl_member without account data
91
-     */
92
-    public function getMemberProperties(): array
93
-    {
94
-        $return = [];
95
-
96
-        Contao\System::loadLanguageFile('tl_member');
97
-        $this->loadDataContainer('tl_member');
98
-
99
-        foreach ($GLOBALS['TL_DCA']['tl_member']['fields'] as $k=>$v)
100
-        {
101
-            if (!empty($v['inputType']) && $v['inputType'] !== 'password')
102
-            {
103
-                $return[$k] = $GLOBALS['TL_DCA']['tl_member']['fields'][$k]['label'][0];
104
-            }
105
-        }
106
-
107
-        return $return;
108
-    }
109
-
110
-    /**
111
-     * Return all sortable fields of table tl_member
112
-     */
113
-    public function getViewableMemberFields(): array
114
-	{
115
-        $return = [];
116
-
117
-        Contao\System::loadLanguageFile('tl_member');
118
-        $this->loadDataContainer('tl_member');
119
-
120
-        foreach ($GLOBALS['TL_DCA']['tl_member']['fields'] as $k=>$v)
121
-        {
122
-            if (!empty($v['inputType']) && $k !== 'avatar' && isset($v['eval']['feViewable']) && $v['eval']['feViewable'] === true)
123
-            {
124
-                $return[$k] = $GLOBALS['TL_DCA']['tl_member']['fields'][$k]['label'][0] . ' ['.$k.']';
125
-            }
126
-        }
127
-
128
-        return $return;
129
-    }
130
-}
131 0
deleted file mode 100644
... ...
@@ -1,22 +0,0 @@
1
-<?xml version="1.0" ?><xliff version="1.1">
2
-  <file datatype="php" original="src/Resources/contao/languages/en/default.php" source-language="en" target-language="de">
3
-    <body>
4
-      <trans-unit id="MSC.emptyMemberList">
5
-        <source>No members could be found.</source>
6
-        <target>Es konnten keine Mitglieder gefunden werden.</target>
7
-      </trans-unit>
8
-      <trans-unit id="MSC.memberDetail">
9
-        <source>More</source>
10
-        <target>Mehr</target>
11
-      </trans-unit>
12
-      <trans-unit id="MSC.deleteAvatar">
13
-        <source>Delete avatar</source>
14
-        <target>Profilbild löschen</target>
15
-      </trans-unit>
16
-      <trans-unit id="MSC.avatarDeleted">
17
-        <source>The avatar was successfully deleted</source>
18
-        <target>Das Profilbild wurde erfolgreich gelöscht</target>
19
-      </trans-unit>
20
-    </body>
21
-  </file>
22
-</xliff>
23 0
deleted file mode 100644
... ...
@@ -1,46 +0,0 @@
1
-<?xml version="1.0" ?><xliff version="1.1">
2
-  <file datatype="php" original="src/Resources/contao/languages/en/modules.php" source-language="en" target-language="de">
3
-    <body>
4
-      <trans-unit id="MOD.member_settings.0">
5
-        <source>Member settings</source>
6
-        <target>Mitglieder-Einstellungen</target>
7
-      </trans-unit>
8
-      <trans-unit id="MOD.member_settings.1">
9
-        <source>Configure member settings</source>
10
-        <target>Mitglieder-Einstellungen vornehmen</target>
11
-      </trans-unit>
12
-      <trans-unit id="FMD.avatar.0">
13
-        <source>Profile picture / Avatar</source>
14
-        <target>Profilbild / Avatar</target>
15
-      </trans-unit>
16
-      <trans-unit id="FMD.avatar.1">
17
-        <source>Displays the profile picture of the member.</source>
18
-        <target>Zeigt das Profilbild des Mitgliedes an.</target>
19
-      </trans-unit>
20
-      <trans-unit id="FMD.deleteAvatar.0">
21
-        <source>Delete avatar</source>
22
-        <target>Profilbild löschen</target>
23
-      </trans-unit>
24
-      <trans-unit id="FMD.deleteAvatar.1">
25
-        <source>Adds a button to delete the avatar of the member.</source>
26
-        <target>Fügt eine Schaltfläche zum Löschen des Profilbildes hinzu.</target>
27
-      </trans-unit>
28
-      <trans-unit id="FMD.memberList.0">
29
-        <source>Memberlist</source>
30
-        <target>Mitgliederliste</target>
31
-      </trans-unit>
32
-      <trans-unit id="FMD.memberList.1">
33
-        <source>Displays a list of members.</source>
34
-        <target>Gibt eine Liste der Mitglieder aus.</target>
35
-      </trans-unit>
36
-      <trans-unit id="FMD.memberReader.0">
37
-        <source>Memberreader</source>
38
-        <target>Mitgliedleser</target>
39
-      </trans-unit>
40
-      <trans-unit id="FMD.memberReader.1">
41
-        <source>Displays a members details.</source>
42
-        <target>Gibt eine Details eines Mitglieds aus.</target>
43
-      </trans-unit>
44
-    </body>
45
-  </file>
46
-</xliff>
47 0
deleted file mode 100644
... ...
@@ -1,22 +0,0 @@
1
-<?xml version="1.0" ?><xliff version="1.1">
2
-  <file datatype="php" original="src/Resources/contao/languages/en/tl_member.php" source-language="en" target-language="de">
3
-    <body>
4
-      <trans-unit id="tl_member.avatar.0">
5
-        <source>Profile picture</source>
6
-        <target>Profilbild</target>
7
-      </trans-unit>
8
-      <trans-unit id="tl_member.avatar.1">
9
-        <source>Here you can choose a profile picture for the member.</source>
10
-        <target>Hier können Sie ein Profilbild für das Mitglied auswählen.</target>
11
-      </trans-unit>
12
-      <trans-unit id="tl_member.settings.0">
13
-        <source>Settings</source>
14
-        <target>Einstellungen</target>
15
-      </trans-unit>
16
-      <trans-unit id="tl_member.settings.1">
17
-        <source>Member settings</source>
18
-        <target>Mitglieder-Einstellungen</target>
19
-      </trans-unit>
20
-    </body>
21
-  </file>
22
-</xliff>
23 0
\ No newline at end of file
24 1
deleted file mode 100644
... ...
@@ -1,30 +0,0 @@
1
-<?xml version="1.0" ?><xliff version="1.1">
2
-  <file datatype="php" original="src/Resources/contao/languages/en/tl_member.php" source-language="en" target-language="de">
3
-    <body>
4
-      <trans-unit id="tl_member_settings.avatar_legend">
5
-        <source>Extended member settings</source>
6
-        <target>Erweiterte Mitgliedseinstellungen</target>
7
-      </trans-unit>
8
-      <trans-unit id="tl_member_settings.defaultAvatar.0">
9
-        <source>Default avatar</source>
10
-        <target>Standard-Profilbild</target>
11
-      </trans-unit>
12
-      <trans-unit id="tl_member_settings.defaultAvatar.1">
13
-        <source>The default avatar is displayed for members who have not uploaded their own profile picture.</source>
14
-        <target>Das Standard-Profilbild wird bei Mitgliedern angezeigt, welches kein eigenes Profilbild hochgeladen haben.</target>
15
-      </trans-unit>
16
-      <trans-unit id="tl_member_settings.order_random">
17
-        <source>Random order</source>
18
-        <target>Zufällige Reihenfolge</target>
19
-      </trans-unit>
20
-      <trans-unit id="tl_member_settings.order_asc">
21
-        <source>Ascending</source>
22
-        <target>Aufsteigend</target>
23
-      </trans-unit>
24
-      <trans-unit id="tl_member_settings.order_desc">
25
-        <source>Descending</source>
26
-        <target>Absteigend</target>
27
-      </trans-unit>
28
-    </body>
29
-  </file>
30
-</xliff>
31 0
deleted file mode 100644
... ...
@@ -1,62 +0,0 @@
1
-<?xml version="1.0" ?><xliff version="1.1">
2
-  <file datatype="php" original="src/Resources/contao/languages/en/tl_module.php" source-language="en" target-language="de">
3
-    <body>
4
-      <trans-unit id="tl_module.ext_order.0">
5
-        <source>Sort order</source>
6
-        <target>Sortierreihenfolge</target>
7
-      </trans-unit>
8
-      <trans-unit id="tl_module.ext_order.1">
9
-        <source>Here you can choose the sort order.</source>
10
-        <target>Hier können Sie die Sortierreihenfolge festlegen.</target>
11
-      </trans-unit>
12
-      <trans-unit id="tl_module.ext_orderField.0">
13
-        <source>Sorting field</source>
14
-        <target>Sortierfeld</target>
15
-      </trans-unit>
16
-      <trans-unit id="tl_module.ext_orderField.1">
17
-        <source>Here you can select the field to be sorted by.</source>
18
-        <target>Hier können Sie das Feld auswählen, nach dem sortiert werden soll.</target>
19
-      </trans-unit>
20
-      <trans-unit id="tl_module.ext_groups.0">
21
-        <source>Groups to show</source>
22
-        <target>Anzuzeigende Gruppen</target>
23
-      </trans-unit>
24
-      <trans-unit id="tl_module.ext_groups.1">
25
-        <source>Here you can select the member groups to be displayed.</source>
26
-        <target>Hier können Sie die Mitgliedergruppen auswählen, die angezeigt werden sollen.</target>
27
-      </trans-unit>
28
-      <trans-unit id="tl_module.memberFields.0">
29
-        <source>Member fields</source>
30
-        <target>Mitglieds-Felder</target>
31
-      </trans-unit>
32
-      <trans-unit id="tl_module.memberFields.1">
33
-        <source>Here you can select the member fields to be displayed.</source>
34
-        <target>Hier können Sie die auszugebenden Mitgliederfelder auswählen.</target>
35
-      </trans-unit>
36
-      <trans-unit id="tl_module.memberFields.0">
37
-        <source>Member fields</source>
38
-        <target>Mitglieds-Felder</target>
39
-      </trans-unit>
40
-      <trans-unit id="tl_module.memberFields.1">
41
-        <source>Here you can select the member fields to be output.</source>
42
-        <target>Hier können Sie die auszugebenden Mitgliederfelder auswählen.</target>
43
-      </trans-unit>
44
-      <trans-unit id="tl_module.memberListTpl.0">
45
-        <source>List template</source>
46
-        <target>Listen-Template</target>
47
-      </trans-unit>
48
-      <trans-unit id="tl_module.memberListTpl.1">
49
-        <source>Here you can set your own member list template.</source>
50
-        <target>Hier können Sie ein eigenes Mitglieder-Listen Template einstellen.</target>
51
-      </trans-unit>
52
-      <trans-unit id="tl_module.memberReaderTpl.0">
53
-        <source>Reader template</source>
54
-        <target>Leser-Template</target>
55
-      </trans-unit>
56
-      <trans-unit id="tl_module.memberReaderTpl.1">
57
-        <source>Here you can set your own member reader template.</source>
58
-        <target>Hier können Sie ein eigenes Mitglieds-Leser Template einstellen.</target>
59
-      </trans-unit>
60
-    </body>
61
-  </file>
62
-</xliff>
63 0
deleted file mode 100644
... ...
@@ -1,18 +0,0 @@
1
-<?xml version="1.0" ?><xliff version="1.1">
2
-  <file datatype="php" original="src/Resources/contao/languages/en/default.php" source-language="en">
3
-    <body>
4
-      <trans-unit id="MSC.emptyMemberList">
5
-        <source>No members could be found.</source>
6
-      </trans-unit>
7
-      <trans-unit id="MSC.memberDetail">
8
-        <source>More</source>
9
-      </trans-unit>
10
-      <trans-unit id="MSC.deleteAvatar">
11
-        <source>Delete avatar</source>
12
-      </trans-unit>
13
-      <trans-unit id="MSC.avatarDeleted">
14
-        <source>The avatar was successfully deleted</source>
15
-      </trans-unit>
16
-    </body>
17
-  </file>
18
-</xliff>
19 0
deleted file mode 100644
... ...
@@ -1,36 +0,0 @@
1
-<?xml version="1.0" ?><xliff version="1.1">
2
-  <file datatype="php" original="src/Resources/contao/languages/en/modules.php" source-language="en">
3
-    <body>
4
-      <trans-unit id="MOD.member_settings.0">
5
-        <source>Member settings</source>
6
-      </trans-unit>
7
-      <trans-unit id="MOD.member_settings.1">
8
-        <source>Configure member settings</source>
9
-      </trans-unit>
10
-      <trans-unit id="FMD.avatar.0">
11
-        <source>Avatar / profile picture</source>
12
-      </trans-unit>
13
-      <trans-unit id="FMD.avatar.1">
14
-        <source>Displays the avatar of the member.</source>
15
-      </trans-unit>
16
-      <trans-unit id="FMD.deleteAvatar.0">
17
-        <source>Delete avatar</source>
18
-      </trans-unit>
19
-      <trans-unit id="FMD.deleteAvatar.1">
20
-        <source>Adds a button to delete the avatar of the member.</source>
21
-      </trans-unit>
22
-      <trans-unit id="FMD.memberList.0">
23
-        <source>Memberlist</source>
24
-      </trans-unit>
25
-      <trans-unit id="FMD.memberList.1">
26
-        <source>Displays a list of members.</source>
27
-      </trans-unit>
28
-      <trans-unit id="FMD.memberReader.0">
29
-        <source>Memberreader</source>
30
-      </trans-unit>
31
-      <trans-unit id="FMD.memberReader.1">
32
-        <source>Displays a members details.</source>
33
-      </trans-unit>
34
-    </body>
35
-  </file>
36
-</xliff>
37 0
deleted file mode 100644
... ...
@@ -1,18 +0,0 @@
1
-<?xml version="1.0" ?><xliff version="1.1">
2
-  <file datatype="php" original="src/Resources/contao/languages/en/tl_member.php" source-language="en">
3
-    <body>
4
-      <trans-unit id="tl_member.avatar.0">
5
-        <source>Avatar</source>
6
-      </trans-unit>
7
-      <trans-unit id="tl_member.avatar.1">
8
-        <source>Here you can choose an avatar for the member.</source>
9
-      </trans-unit>
10
-      <trans-unit id="tl_member.settings.0">
11
-        <source>Settings</source>
12
-      </trans-unit>
13
-      <trans-unit id="tl_member.settings.1">
14
-        <source>Member settings</source>
15
-      </trans-unit>
16
-    </body>
17
-  </file>
18
-</xliff>
19 0
\ No newline at end of file
20 1
deleted file mode 100644
... ...
@@ -1,24 +0,0 @@
1
-<?xml version="1.0" ?><xliff version="1.1">
2
-  <file datatype="php" original="src/Resources/contao/languages/en/tl_member.php" source-language="en">
3
-    <body>
4
-      <trans-unit id="tl_member_settings.avatar_legend">
5
-        <source>Extended member settings</source>
6
-      </trans-unit>
7
-      <trans-unit id="tl_member_settings.defaultAvatar.0">
8
-        <source>Default avatar</source>
9
-      </trans-unit>
10
-      <trans-unit id="tl_member_settings.defaultAvatar.1">
11
-        <source>The default avatar is displayed for members who have not uploaded their own profile picture.</source>
12
-      </trans-unit>
13
-      <trans-unit id="tl_member_settings.order_random">
14
-        <source>Random order</source>
15
-      </trans-unit>
16
-      <trans-unit id="tl_member_settings.order_asc">
17
-        <source>Ascending</source>
18
-      </trans-unit>
19
-      <trans-unit id="tl_member_settings.order_desc">
20
-        <source>Descending</source>
21
-      </trans-unit>
22
-    </body>
23
-  </file>
24
-</xliff>
25 0
deleted file mode 100644
... ...
@@ -1,48 +0,0 @@
1
-<?xml version="1.0" ?><xliff version="1.1">
2
-  <file datatype="php" original="src/Resources/contao/languages/en/tl_module.php" source-language="en">
3
-    <body>
4
-      <trans-unit id="tl_module.ext_order.0">
5
-        <source>Sort order</source>
6
-      </trans-unit>
7
-      <trans-unit id="tl_module.ext_order.1">
8
-        <source>Here you can choose the sort order.</source>
9
-      </trans-unit>
10
-      <trans-unit id="tl_module.ext_orderField.0">
11
-        <source>Sorting field</source>
12
-      </trans-unit>
13
-      <trans-unit id="tl_module.ext_orderField.1">
14
-        <source>Here you can select the field to be sorted by.</source>
15
-      </trans-unit>
16
-      <trans-unit id="tl_module.ext_groups.0">
17
-        <source>Groups to show</source>
18
-      </trans-unit>
19
-      <trans-unit id="tl_module.ext_groups.1">
20
-        <source>Here you can select the member groups to be displayed.</source>
21
-      </trans-unit>
22
-      <trans-unit id="tl_module.memberFields.0">
23
-        <source>Member fields</source>
24
-      </trans-unit>
25
-      <trans-unit id="tl_module.memberFields.1">
26
-        <source>Here you can select the member fields to be displayed.</source>
27
-      </trans-unit>
28
-      <trans-unit id="tl_module.memberFields.0">
29
-        <source>Member fields</source>
30
-      </trans-unit>
31
-      <trans-unit id="tl_module.memberFields.1">
32
-        <source>Here you can select the member fields to be output.</source>
33
-      </trans-unit>
34
-      <trans-unit id="tl_module.memberListTpl.0">
35
-        <source>List template</source>
36
-      </trans-unit>
37
-      <trans-unit id="tl_module.memberListTpl.1">
38
-        <source>Here you can set your own member list template.</source>
39
-      </trans-unit>
40
-      <trans-unit id="tl_module.memberReaderTpl.0">
41
-        <source>Reader template</source>
42
-      </trans-unit>
43
-      <trans-unit id="tl_module.memberReaderTpl.1">
44
-        <source>Here you can set your own member reader template.</source>
45
-      </trans-unit>
46
-    </body>
47
-  </file>
48
-</xliff>
49 0
deleted file mode 100644
... ...
@@ -1,88 +0,0 @@
1
-<?php
2
-
3
-declare(strict_types=1);
4
-
5
-/*
6
- * This file is part of Oveleon ContaoMemberExtension Bundle.
7
- *
8
- * @package     contao-member-extension-bundle
9
- * @license     MIT
10
- * @author      Daniele Sciannimanica   <https://github.com/doishub>
11
- * @author      Fabian Ekert            <https://github.com/eki89>
12
- * @author      Sebastian Zoglowek      <https://github.com/zoglo>
13
- * @copyright   Oveleon                 <https://www.oveleon.de/>
14
- */
15
-
16
-namespace Oveleon\ContaoMemberExtensionBundle;
17
-
18
-use Contao\BackendTemplate;
19
-use Contao\Config;
20
-use Contao\FilesModel;
21
-use Contao\FrontendUser;
22
-use Contao\MemberModel;
23
-use Contao\Module;
24
-use Contao\System;
25
-
26
-/**
27
- * Class ModuleAvatar
28
- *
29
- * @author Fabian Ekert <fabian@oveleon.de>
30
- * @author Sebastian Zoglowek <https://github.com/zoglo>
31
- */
32
-class ModuleAvatar extends ModuleMemberExtension
33
-{
34
-    /**
35
-     * Template.
36
-     *
37
-     * @var string
38
-     */
39
-    protected $strTemplate = 'memberExtension_avatar';
40
-
41
-    /**
42
-     * Return a wildcard in the back end
43
-     *
44
-     * @return string
45
-     */
46
-    public function generate()
47
-    {
48
-        $request = System::getContainer()->get('request_stack')->getCurrentRequest();
49
-
50
-        if ($request && System::getContainer()->get('contao.routing.scope_matcher')->isBackendRequest($request))
51
-        {
52
-            $objTemplate = new BackendTemplate('be_wildcard');
53
-            $objTemplate->wildcard = '### ' . mb_strtoupper($GLOBALS['TL_LANG']['FMD']['avatar'][0], 'UTF-8') . ' ###';
54
-            $objTemplate->title = $this->headline;
55
-            $objTemplate->id = $this->id;
56
-            $objTemplate->link = $this->name;
57
-            $objTemplate->href = 'contao/main.php?do=themes&amp;table=tl_module&amp;act=edit&amp;id=' . $this->id;
58
-
59
-            return $objTemplate->parse();
60
-        }
61
-
62
-        // Return if user is not logged in
63
-        $tokenChecker = System::getContainer()->get('contao.security.token_checker');
64
-        $blnFeUserLoggedIn = $tokenChecker->hasFrontendUser();
65
-
66
-        if (!$blnFeUserLoggedIn)
67
-        {
68
-            return '';
69
-        }
70
-
71
-        $this->strTemplate = $this->customTpl ?: 'memberExtension_avatar';
72
-
73
-        return parent::generate();
74
-    }
75
-
76
-    /**
77
-     * Generate the module
78
-     */
79
-    protected function compile()
80
-    {
81
-        $objTemplate = $this->Template;
82
-
83
-        $this->import(FrontendUser::class, 'User');
84
-        $objMember = MemberModel::findByPk($this->User->id);
85
-
86
-        Member::parseMemberAvatar($objMember, $objTemplate, $this->imgSize);
87
-    }
88
-}
89 0
deleted file mode 100644
... ...
@@ -1,135 +0,0 @@
1
-<?php
2
-
3
-declare(strict_types=1);
4
-
5
-/*
6
- * This file is part of Oveleon ContaoMemberExtension Bundle.
7
- *
8
- * @package     contao-member-extension-bundle
9
- * @license     MIT
10
- * @author      Daniele Sciannimanica   <https://github.com/doishub>
11
- * @author      Fabian Ekert            <https://github.com/eki89>
12
- * @author      Sebastian Zoglowek      <https://github.com/zoglo>
13
- * @copyright   Oveleon                 <https://www.oveleon.de/>
14
- */
15
-
16
-namespace Oveleon\ContaoMemberExtensionBundle;
17
-
18
-use Contao\BackendTemplate;
19
-use Contao\Config;
20
-use Contao\FrontendUser;
21
-use Contao\Input;
22
-use Contao\MemberModel;
23
-use Contao\Module;
24
-use Contao\StringUtil;
25
-use Contao\System;
26
-
27
-/**
28
- * Class ModuleDeleteAvatar
29
- *
30
- * @author Sebastian Zoglowek <https://github.com/zoglo>
31
- */
32
-class ModuleDeleteAvatar extends Module
33
-{
34
-    /**
35
-     * Template.
36
-     *
37
-     * @var string
38
-     */
39
-    protected $strTemplate = 'memberExtension_deleteAvatar';
40
-
41
-    /**
42
-     * Return a wildcard in the back end
43
-     *
44
-     * @return string
45
-     */
46
-    public function generate()
47
-    {
48
-        $container = System::getContainer();
49
-
50
-        $request = System::getContainer()->get('request_stack')->getCurrentRequest();
51
-
52
-        if ($request && System::getContainer()->get('contao.routing.scope_matcher')->isBackendRequest($request))
53
-        {
54
-            $objTemplate = new BackendTemplate('be_wildcard');
55
-            $objTemplate->wildcard = '### ' . mb_strtoupper($GLOBALS['TL_LANG']['FMD']['deleteAvatar'][0] ?? '', 'UTF-8') . ' ###';
56
-            $objTemplate->title = $this->headline;
57
-            $objTemplate->id = $this->id;
58
-            $objTemplate->link = $this->name;
59
-            $objTemplate->href = 'contao/main.php?do=themes&amp;table=tl_module&amp;act=edit&amp;id=' . $this->id;
60
-
61
-            return $objTemplate->parse();
62
-        }
63
-
64
-        // Set the item from the auto_item parameter
65
-        if (!isset($_GET['items']) && isset($_GET['auto_item']) && Config::get('useAutoItem'))
66
-        {
67
-            Input::setGet('items', Input::get('auto_item'));
68
-        }
69
-
70
-        // Return if there is no logged-in user
71
-        if (!$container->get('contao.security.token_checker')->hasFrontendUser())
72
-        {
73
-            return '';
74
-        }
75
-
76
-        $this->import(FrontendUser::class, 'User');
77
-        $objMember = MemberModel::findByPk($this->User->id);
78
-
79
-        if(null === $objMember)
80
-        {
81
-            return '';
82
-        }
83
-
84
-        // Confirmation message
85
-        $session = System::getContainer()->get('session');
86
-        $flashBag = $session->getFlashBag();
87
-
88
-        // Return if there is no flashbag message or an avatar
89
-        if (!($session->isStarted() && $flashBag->has('mod_avatar_deleted')) && !$objMember->avatar)
90
-        {
91
-            return '';
92
-        }
93
-
94
-        return parent::generate();
95
-    }
96
-
97
-    /**
98
-     * Generate the module
99
-     */
100
-    protected function compile()
101
-    {
102
-        $strFormId = 'deleteAvatar_' . $this->id;
103
-        $session = System::getContainer()->get('session');
104
-        $flashBag = $session->getFlashBag();
105
-
106
-        // Get form submit
107
-        if (Input::post('FORM_SUBMIT') == $strFormId)
108
-        {
109
-            $this->import(FrontendUser::class, 'User');
110
-            $objMember = MemberModel::findByPk($this->User->id);
111
-
112
-            // Delete avatar if it exists
113
-            if(!!$objMember->avatar)
114
-            {
115
-                Member::deleteAvatar($objMember);
116
-                // Unset avatar
117
-                $objMember->avatar = null;
118
-                $objMember->save();
119
-
120
-                // Set message for deletion feedback
121
-                $flashBag->set('mod_avatar_deleted', $GLOBALS['TL_LANG']['MSC']['avatarDeleted']);
122
-                $this->reload();
123
-            }
124
-        }
125
-
126
-        // Confirmation message
127
-        if($session->isStarted() && $flashBag->has('mod_avatar_deleted')) {
128
-            $arrMessages = $flashBag->get('mod_avatar_deleted');
129
-            $this->Template->message = $arrMessages[0];
130
-        }
131
-
132
-        $this->Template->formId = $strFormId;
133
-        $this->Template->slabel = StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['deleteAvatar']);
134
-    }
135
-}
136 0
deleted file mode 100644
... ...
@@ -1,178 +0,0 @@
1
-<?php
2
-
3
-declare(strict_types=1);
4
-
5
-/*
6
- * This file is part of Oveleon ContaoMemberExtension Bundle.
7
- *
8
- * @package     contao-member-extension-bundle
9
- * @license     MIT
10
- * @author      Daniele Sciannimanica   <https://github.com/doishub>
11
- * @author      Fabian Ekert            <https://github.com/eki89>
12
- * @author      Sebastian Zoglowek      <https://github.com/zoglo>
13
- * @copyright   Oveleon                 <https://www.oveleon.de/>
14
- */
15
-
16
-namespace Oveleon\ContaoMemberExtensionBundle;
17
-
18
-use Contao\Config;
19
-use Contao\Date;
20
-use Contao\Environment;
21
-use Contao\MemberGroupModel;
22
-use Contao\MemberModel;
23
-use Contao\Module;
24
-use Contao\PageModel;
25
-use Contao\StringUtil;
26
-use Contao\System;
27
-
28
-/**
29
- * Parent class for member modules.
30
- *
31
- * @author Daniele Sciannimanica <https://github.com/doishub>
32
- */
33
-abstract class ModuleMemberExtension extends Module
34
-{
35
-    /**
36
-     * Parse member template
37
-     *
38
-     * @param $objMember
39
-     * @param $objTemplate
40
-     * @param $arrMemberFields
41
-     * @param $strImgSize
42
-     * @return string
43
-     */
44
-    protected function parseMemberTemplate($objMember, $objTemplate, $arrMemberFields, $strImgSize): string
45
-    {
46
-        System::loadLanguageFile('default');
47
-        System::loadLanguageFile('tl_member');
48
-        System::loadLanguageFile('countries');
49
-        System::loadLanguageFile('languages');
50
-
51
-        $arrFields = [];
52
-
53
-        foreach ($arrMemberFields as $field)
54
-        {
55
-            switch($field)
56
-            {
57
-                /*case 'homeDir':
58
-                case 'assignDir':
59
-                    break;*/
60
-
61
-                case 'avatar':
62
-                    Member::parseMemberAvatar($objMember, $objTemplate, $strImgSize);
63
-                    break;
64
-
65
-                default:
66
-                    if($varValue = $objMember->{$field})
67
-                    {
68
-                        if (\is_array(($arrValue = StringUtil::deserialize($varValue))))
69
-                        {
70
-                            $arrFields[$field] = implode(",", $arrValue);
71
-                        }
72
-                        else
73
-                        {
74
-                            $arrFields[$field] = $varValue;
75
-                        }
76
-                        //self::parseMemberDetails($arrFields, $field, $varValue);
77
-                    }
78
-            }
79
-        }
80
-
81
-        $objTemplate->fields = $arrFields;
82
-
83
-        if($this->jumpTo)
84
-        {
85
-            $objTemplate->link = $this->generateMemberUrl($objMember);
86
-        }
87
-
88
-        return $objTemplate->parse();
89
-    }
90
-
91
-    /**
92
-     * Generate a URL and return it as string
93
-     *
94
-     * @param MemberModel $objMember
95
-     *
96
-     * @return string
97
-     */
98
-    protected function generateMemberUrl(MemberModel $objMember): string
99
-    {
100
-        $objPage = PageModel::findPublishedById($this->jumpTo);
101
-
102
-        if (!$objPage instanceof PageModel)
103
-        {
104
-            $strLink = ampersand(Environment::get('request'));
105
-        }
106
-        else
107
-        {
108
-            $params = (Config::get('useAutoItem') ? '/' : '/items/') . ($objMember->alias ?: $objMember->id);
109
-            $strLink = ampersand($objPage->getFrontendUrl($params));
110
-        }
111
-
112
-        return $strLink;
113
-    }
114
-
115
-    protected function parseMemberDetails(&$arrFields, $field, $value)
116
-    {
117
-        $strReturn = sprintf('<span class="label">%s: </span>',$GLOBALS['TL_LANG']['tl_member'][$field][0] ?? null);
118
-
119
-        if (!\is_array(($arrValue = StringUtil::deserialize($value))))
120
-        {
121
-            switch ($field) {
122
-                case 'gender':
123
-                    $strReturn .= $GLOBALS['TL_LANG']['MSC'][$value] ?? $value;
124
-                    break;
125
-
126
-                case 'email':
127
-                    $strEmail = StringUtil::encodeEmail($value);
128
-                    $strReturn .= '<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;' . $strEmail . '" title="' . $strEmail . '">' . preg_replace('/\?.*$/', '', $strEmail) . '</a>';
129
-                    break;
130
-
131
-                case 'phone':
132
-                case 'mobile':
133
-                case 'fax':
134
-                    $strTel = preg_replace('/[^a-z\d+]/i', '', (string)$value);
135
-                    $strReturn .= '<a href="tel:' . $strTel . '" title="' . $value . '">' . $value . '</a>';
136
-                    break;
137
-
138
-                case 'website':
139
-                    $strUrl = $value;
140
-
141
-                    if (strncmp($value, 'http://', 7) !== 0 || strncmp($value, 'https://', 8) !== 0) {
142
-                        $strUrl = 'https://' . $value;
143
-                    }
144
-
145
-                    $strReturn .= '<a href="' . $strUrl . '" title="' . $value . '" target="blank noopener" rel="noreferer">' . $value . '</a>';
146
-                    break;
147
-
148
-                case 'dateOfBirth':
149
-                    $strReturn .= Date::parse(Config::get('dateFormat'), $value) ?? $value;
150
-                    break;
151
-
152
-                case 'country':
153
-                    $strReturn .= $GLOBALS['TL_LANG']['CNT'][$value] ?? $value;
154
-                    break;
155
-
156
-                case 'language':
157
-                    $strReturn .= $GLOBALS['TL_LANG']['LNG'][$value] ?? $value;
158
-                    break;
159
-
160
-                default:
161
-                    $strReturn .= $value;
162
-            }
163
-        }
164
-        else if ('groups' === $field)
165
-        {
166
-            $arrReturn = [];
167
-
168
-            foreach ($arrValue as $value)
169
-            {
170
-                $arrReturn[] = MemberGroupModel::findById($value)->name;
171
-            }
172
-
173
-            $strReturn .= implode(", ", $arrReturn);
174
-        }
175
-
176
-        $arrFields[$field] = $strReturn;
177
-    }
178
-}
179 0
deleted file mode 100644
... ...
@@ -1,223 +0,0 @@
1
-<?php
2
-
3
-declare(strict_types=1);
4
-
5
-/*
6
- * This file is part of Oveleon ContaoMemberExtension Bundle.
7
- *
8
- * @package     contao-member-extension-bundle
9
- * @license     MIT
10
- * @author      Daniele Sciannimanica   <https://github.com/doishub>
11
- * @author      Fabian Ekert            <https://github.com/eki89>
12
- * @author      Sebastian Zoglowek      <https://github.com/zoglo>
13
- * @copyright   Oveleon                 <https://www.oveleon.de/>
14
- */
15
-
16
-namespace Oveleon\ContaoMemberExtensionBundle;
17
-
18
-use Contao\BackendTemplate;
19
-use Contao\Config;
20
-use Contao\CoreBundle\Exception\PageNotFoundException;
21
-use Contao\Environment;
22
-use Contao\FrontendTemplate;
23
-use Contao\Input;
24
-use Contao\MemberModel;
25
-use Contao\Model\Collection;
26
-use Contao\Pagination;
27
-use Contao\StringUtil;
28
-use Contao\System;
29
-
30
-/**
31
- * Class ModuleMemberList
32
- *
33
- * @property string $ext_order order of list items
34
- * @property string ext_orderField order field for list items
35
- * @property string $ext_groups considered member groups
36
- * @property string $memberFields Fields to be displayed
37
- * @property string $memberListTpl Frontend list template
38
- */
39
-class ModuleMemberList extends ModuleMemberExtension
40
-{
41
-
42
-    /**
43
-     * Template
44
-     * @var string
45
-     */
46
-    protected $strTemplate = 'mod_memberList';
47
-
48
-    /**
49
-     * Template
50
-     * @var string
51
-     */
52
-    protected $strMemberTemplate = 'memberExtension_list_default';
53
-
54
-    /**
55
-     * Return a wildcard in the back end
56
-     *
57
-     * @return string
58
-     */
59
-    public function generate()
60
-    {
61
-        $request = System::getContainer()->get('request_stack')->getCurrentRequest();
62
-
63
-        if ($request && System::getContainer()->get('contao.routing.scope_matcher')->isBackendRequest($request))
64
-        {
65
-            $objTemplate = new BackendTemplate('be_wildcard');
66
-            $objTemplate->wildcard = '### ' . mb_strtoupper($GLOBALS['TL_LANG']['FMD']['memberList'][0], 'UTF-8') . ' ###';
67
-            $objTemplate->title = $this->headline;
68
-            $objTemplate->id = $this->id;
69
-            $objTemplate->link = $this->name;
70
-            $objTemplate->href = 'contao/main.php?do=themes&amp;table=tl_module&amp;act=edit&amp;id=' . $this->id;
71
-
72
-            return $objTemplate->parse();
73
-        }
74
-
75
-        return parent::generate();
76
-    }
77
-
78
-    /**
79
-     * Generate the module
80
-     */
81
-    protected function compile()
82
-    {
83
-        $limit = null;
84
-        $offset = 0;
85
-
86
-        $arrGroups = StringUtil::deserialize($this->ext_groups);
87
-
88
-        if(empty($arrGroups) || !\is_array($arrGroups))
89
-        {
90
-            $this->Template->empty = $GLOBALS['TL_LANG']['MSC']['emptyMemberList'];
91
-            return;
92
-        }
93
-
94
-        $objTemplate = new FrontendTemplate($this->memberListTpl ?: $this->strMemberTemplate);
95
-
96
-        $objMembers = $this->getMembers();
97
-
98
-        $intTotal = 0;
99
-
100
-        $arrMembers = [];
101
-
102
-        if(null !== $objMembers)
103
-        {
104
-            while($objMembers->next())
105
-            {
106
-                $objMember = $objMembers->current();
107
-
108
-                if(!$this->checkMemberGroups($arrGroups, $objMember))
109
-                {
110
-                    continue;
111
-                }
112
-
113
-                $intTotal += 1;
114
-
115
-                $arrMemberFields = StringUtil::deserialize($this->memberFields, true);
116
-                $objTemplate->setData($objMember->row());
117
-
118
-                $arrMembers[] = $this->parseMemberTemplate($objMember, $objTemplate, $arrMemberFields, $this->imgSize);
119
-            }
120
-        }
121
-
122
-        $total = $intTotal - $offset;
123
-
124
-        if ($this->numberOfItems > 0)
125
-        {
126
-            $limit = $this->numberOfItems;
127
-        }
128
-
129
-        if ($this->perPage > 0 && (!isset($limit) || $this->numberOfItems > $this->perPage))
130
-        {
131
-            if (isset($limit))
132
-            {
133
-                $total = min($limit, $total);
134
-            }
135
-
136
-            $id = 'page_n' . $this->id;
137
-            $page = Input::get($id) ?? 1;
138
-
139
-            if ($page < 1 || $page > max(ceil($total/$this->perPage), 1))
140
-            {
141
-                throw new PageNotFoundException('Page not found: ' . Environment::get('uri'));
142
-            }
143
-
144
-            $limit = $this->perPage;
145
-            $offset += (max($page, 1) - 1) * $this->perPage;
146
-            $skip = 0;
147
-
148
-            if ($offset + $limit > $total + $skip)
149
-            {
150
-                $limit = $total + $skip - $offset;
151
-            }
152
-
153
-            $arrMembers = \array_slice($arrMembers, $offset, ((int) $limit ?: $intTotal), true);
154
-
155
-            $objPagination = new Pagination($total, $this->perPage, Config::get('maxPaginationLinks'), $id);
156
-            $this->Template->pagination = $objPagination->generate("\n  ");
157
-        }
158
-
159
-        if(empty($arrMembers))
160
-        {
161
-            $this->Template->empty = $GLOBALS['TL_LANG']['MSC']['emptyMemberList'];
162
-        }
163
-
164
-        $this->Template->members = $arrMembers;
165
-    }
166
-
167
-    /**
168
-     * Checks whether a member is in any given group
169
-     *
170
-     * @param array $arrGroups
171
-     * @param MemberModel $objMember
172
-     * @return bool
173
-     */
174
-    private function checkMemberGroups(array $arrGroups, MemberModel $objMember): bool
175
-    {
176
-        if(empty($arrGroups))
177
-        {
178
-            return false;
179
-        }
180
-
181
-        $arrMemberGroups = StringUtil::deserialize($objMember->groups);
182
-
183
-        if(!\is_array($arrMemberGroups) || !\count(array_intersect($arrGroups, $arrMemberGroups)))
184
-        {
185
-            return false;
186
-        }
187
-
188
-        return true;
189
-    }
190
-
191
-    /**
192
-     * Get members
193
-     *
194
-     * @return Collection|MemberModel|null
195
-     */
196
-    private function getMembers()
197
-    {
198
-        $t = MemberModel::getTable();
199
-        $arrOptions = ['order' => ''];
200
-
201
-        if (!!$this->ext_orderField)
202
-        {
203
-            $arrOptions['order'] .= "$t.$this->ext_orderField ";
204
-        }
205
-
206
-        switch ($this->ext_order)
207
-        {
208
-            case 'order_random':
209
-                $arrOptions['order'] .= "RAND()";
210
-                break;
211
-
212
-            case 'order_desc':
213
-                $arrOptions['order'] .= "DESC";
214
-                break;
215
-
216
-            case 'order_asc':
217
-            default:
218
-                break;
219
-        }
220
-
221
-        return MemberModel::findBy(["$t.disable=''"], null, $arrOptions);
222
-    }
223
-}
224 0
deleted file mode 100644
... ...
@@ -1,113 +0,0 @@
1
-<?php
2
-
3
-declare(strict_types=1);
4
-
5
-/*
6
- * This file is part of Oveleon ContaoMemberExtension Bundle.
7
- *
8
- * @package     contao-member-extension-bundle
9
- * @license     MIT
10
- * @author      Daniele Sciannimanica   <https://github.com/doishub>
11
- * @author      Fabian Ekert            <https://github.com/eki89>
12
- * @author      Sebastian Zoglowek      <https://github.com/zoglo>
13
- * @copyright   Oveleon                 <https://www.oveleon.de/>
14
- */
15
-
16
-namespace Oveleon\ContaoMemberExtensionBundle;
17
-
18
-use Contao\BackendTemplate;
19
-use Contao\Config;
20
-use Contao\CoreBundle\Exception\PageNotFoundException;
21
-use Contao\Environment;
22
-use Contao\FrontendTemplate;
23
-use Contao\Input;
24
-use Contao\MemberModel;
25
-use Contao\StringUtil;
26
-use Contao\System;
27
-
28
-/**
29
- * Class ModuleMemberList
30
- * 
31
- * @property string $ext_groups considered member groups
32
- * @property string $memberFields Fields to be displayed
33
- * @property string $memberReaderTpl Frontend reader template
34
- */
35
-class ModuleMemberReader extends ModuleMemberExtension
36
-{
37
-
38
-	/**
39
-	 * Template
40
-	 * @var string
41
-	 */
42
-	protected $strTemplate = 'mod_memberReader';
43
-
44
-	/**
45
-	 * Template
46
-	 * @var string
47
-	 */
48
-	protected $strMemberTemplate = 'memberExtension_reader_full';
49
-
50
-	/**
51
-	 * Return a wildcard in the back end
52
-	 *
53
-	 * @return string
54
-	 */
55
-	public function generate()
56
-	{
57
-        $request = System::getContainer()->get('request_stack')->getCurrentRequest();
58
-
59
-        if ($request && System::getContainer()->get('contao.routing.scope_matcher')->isBackendRequest($request))
60
-        {
61
-            $objTemplate = new BackendTemplate('be_wildcard');
62
-			$objTemplate->wildcard = '### ' . mb_strtoupper($GLOBALS['TL_LANG']['FMD']['memberList'][0], 'UTF-8') . ' ###';
63
-			$objTemplate->title = $this->headline;
64
-			$objTemplate->id = $this->id;
65
-			$objTemplate->link = $this->name;
66
-			$objTemplate->href = 'contao/main.php?do=themes&amp;table=tl_module&amp;act=edit&amp;id=' . $this->id;
67
-
68
-			return $objTemplate->parse();
69
-		}
70
-
71
-        // Set the item from the auto_item parameter
72
-        if (!isset($_GET['items']) && isset($_GET['auto_item']) && Config::get('useAutoItem'))
73
-        {
74
-            Input::setGet('items', Input::get('auto_item'));
75
-        }
76
-
77
-		return parent::generate();
78
-	}
79
-
80
-	/**
81
-	 * Generate the module
82
-	 */
83
-	protected function compile()
84
-	{
85
-        $this->Template->referer = 'javascript:history.go(-1)';
86
-        $this->Template->back = $GLOBALS['TL_LANG']['MSC']['goBack'];
87
-
88
-        // Get the member
89
-        $objMember = MemberModel::findByIdOrAlias(Input::get('items'));
90
-
91
-        // The member does not exist and is not deactivated
92
-        if ($objMember === null || $objMember->disable)
93
-        {
94
-            throw new PageNotFoundException('Page not found: ' . Environment::get('uri'));
95
-        }
96
-
97
-        // Check for group intersection
98
-        $arrGroups = StringUtil::deserialize($this->ext_groups);
99
-        $memberGroups = StringUtil::deserialize($objMember->groups);
100
-
101
-        if (empty($arrGroups) || !\is_array($arrGroups) || !\count(array_intersect($arrGroups, $memberGroups)))
102
-        {
103
-            throw new PageNotFoundException('Page not found: ' . Environment::get('uri'));
104
-        }
105
-
106
-        $arrMemberFields = StringUtil::deserialize($this->memberFields, true);
107
-
108
-        $objTemplate = new FrontendTemplate($this->memberReaderTpl ?: $this->strMemberTemplate);
109
-        $objTemplate->setData($objMember->row());
110
-
111
-        $this->Template->member = $this->parseMemberTemplate($objMember, $objTemplate, $arrMemberFields, $this->imgSize);
112
-	}
113
-}
114 0
deleted file mode 100644
... ...
@@ -1,8 +0,0 @@
1
-<figure class="image_container">
2
-
3
-  <?php if($this->addFallbackImage): ?>
4
-    <img src="<?= $this->singleSRC; ?>" width="200" height="200" itemprop="image">
5
-  <?php else: ?>
6
-    <?php $this->insert('picture_default', $this->picture); ?>
7
-  <?php endif; ?>
8
-</figure>
9 0
deleted file mode 100644
... ...
@@ -1,7 +0,0 @@
1
-<?php $this->extend('block_searchable'); ?>
2
-
3
-<?php $this->block('content'); ?>
4
-
5
-<?php $this->insert('memberExtension_image', $this->arrData); ?>
6
-
7
-<?php $this->endblock(); ?>
8 0
deleted file mode 100644
... ...
@@ -1,23 +0,0 @@
1
-<?php $this->extend('block_unsearchable'); ?>
2
-
3
-<?php $this->block('content'); ?>
4
-
5
-<!-- indexer::stop -->
6
-
7
-  <?php if ($this->message): ?>
8
-    <p class="tl_confirm"><?= $this->message ?></p>
9
-  <?php else: ?>
10
-    <form id="<?= $this->formId ?>" method="post">
11
-      <div class="formbody">
12
-        <input type="hidden" name="FORM_SUBMIT" value="<?= $this->formId ?>">
13
-        <input type="hidden" name="REQUEST_TOKEN" value="{{request_token}}">
14
-        <div class="widget widget-submit">
15
-          <button type="submit" class="submit"><?= $this->slabel ?></button>
16
-        </div>
17
-      </div>
18
-    </form>
19
-  <?php endif; ?>
20
-
21
-<!-- indexer::continue -->
22
-
23
-<?php $this->endblock(); ?>
24 0
deleted file mode 100644
... ...
@@ -1,16 +0,0 @@
1
-<div class="member_list_default">
2
-
3
-  <?php if($this->addImage): ?>
4
-    <?php $this->insert('memberExtension_image', $this->arrData); ?>
5
-  <?php endif; ?>
6
-
7
-  <ul>
8
-    <?php foreach ($this->fields as $k => $v): ?>
9
-      <li class="<?= $k ?>"><?= $v ?></li>
10
-    <?php endforeach; ?>
11
-  </ul>
12
-
13
-  <?php if($this->link): ?>
14
-    <a href="<?=$this->link?>"><?=$GLOBALS['TL_LANG']['MSC']['memberDetail']?></a>
15
-  <?php endif; ?>
16
-</div>
17 0
deleted file mode 100644
... ...
@@ -1,12 +0,0 @@
1
-<div class="member_reader_full">
2
-
3
-  <?php if($this->addImage): ?>
4
-    <?php $this->insert('memberExtension_image', $this->arrData); ?>
5
-  <?php endif; ?>
6
-
7
-  <ul>
8
-    <?php foreach ($this->fields as $k => $v): ?>
9
-      <li class="<?= $k ?>"><?= $v ?></li>
10
-    <?php endforeach; ?>
11
-  </ul>
12
-</div>
13 0
deleted file mode 100644
... ...
@@ -1,14 +0,0 @@
1
-<?php $this->extend('block_unsearchable'); ?>
2
-
3
-<?php $this->block('content'); ?>
4
-
5
-<?php if (empty($this->members)): ?>
6
-    <p class="empty message"><?=$this->empty?></p>
7
-<?php else: ?>
8
-    <?php foreach ($this->members as $member): ?>
9
-      <?=$member?>
10
-    <?php endforeach; ?>
11
-    <?= $this->pagination ?>
12
-<?php endif; ?>
13
-
14
-<?php $this->endblock(); ?>
15 0
deleted file mode 100644
... ...
@@ -1,11 +0,0 @@
1
-<?php $this->extend('block_unsearchable'); ?>
2
-
3
-<?php $this->block('content'); ?>
4
-
5
-<?=$this->member?>
6
-
7
-<!-- indexer::stop -->
8
-<p class="back"><a href="<?= $this->referer ?>" title="<?= $this->back ?>"><?= $this->back ?></a></p>
9
-<!-- indexer::continue -->
10
-
11
-<?php $this->endblock(); ?>
12 0
deleted file mode 100644
13 1
Binary files a/src/Resources/public/avatar.png and /dev/null differ