Proyectos de Subversion LeadersLinked - Backend

Rev

Rev 17219 | Rev 17223 | Ir a la última revisión | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 www 1
<?php
2
declare(strict_types=1);
3
 
4
namespace LeadersLinked\Controller;
5
 
6
use Laminas\Mvc\Controller\AbstractActionController;
7
use Laminas\View\Model\JsonModel;
17184 stevensc 8
use Laminas\View\Model\ViewModel;
17216 stevensc 9
use Laminas\Hydrator\ObjectPropertyHydrator;
1 www 10
use LeadersLinked\Library\Functions;
17002 efrain 11
use LeadersLinked\Mapper\MicrolearningTopicMapper;
17101 stevensc 12
use LeadersLinked\Mapper\MicrolearningCapsuleMapper;
17002 efrain 13
use LeadersLinked\Model\MicrolearningTopic;
14
use LeadersLinked\Form\Microlearning\TopicAddForm;
15
use LeadersLinked\Form\Microlearning\TopicEditForm;
17222 stevensc 16
use LeadersLinked\Hydrator\ObjectPropertyHydrator as HydratorObjectPropertyHydrator;
17002 efrain 17
use LeadersLinked\Library\Storage;
17107 stevensc 18
use LeadersLinked\Model\MicrolearningTopicCapsule;
19
use LeadersLinked\Mapper\MicrolearningTopicCapsuleMapper;
17178 stevensc 20
use LeadersLinked\Mapper\MicrolearningUserProgressMapper;
17187 stevensc 21
use LeadersLinked\Mapper\QueryMapper;
22
use LeadersLinked\Mapper\UserMapper;
23
use LeadersLinked\Mapper\MicrolearningTopicUserMapper;
24
use LeadersLinked\Model\MicrolearningTopicUser;
1 www 25
 
26
class MicrolearningTopicController extends AbstractActionController
27
{
28
    /**
29
     *
16769 efrain 30
     * @var \Laminas\Db\Adapter\AdapterInterface
1 www 31
     */
32
    private $adapter;
33
 
34
    /**
35
     *
16769 efrain 36
     * @var \LeadersLinked\Cache\CacheInterface
1 www 37
     */
16769 efrain 38
    private $cache;
39
 
40
 
41
    /**
42
     *
43
     * @var \Laminas\Log\LoggerInterface
44
     */
1 www 45
    private $logger;
46
 
47
    /**
48
     *
49
     * @var array
50
     */
51
    private $config;
52
 
16769 efrain 53
 
1 www 54
    /**
55
     *
16769 efrain 56
     * @var \Laminas\Mvc\I18n\Translator
57
     */
58
    private $translator;
59
 
60
 
61
    /**
62
     *
63
     * @param \Laminas\Db\Adapter\AdapterInterface $adapter
64
     * @param \LeadersLinked\Cache\CacheInterface $cache
65
     * @param \Laminas\Log\LoggerInterface LoggerInterface $logger
1 www 66
     * @param array $config
16769 efrain 67
     * @param \Laminas\Mvc\I18n\Translator $translator
1 www 68
     */
16769 efrain 69
    public function __construct($adapter, $cache, $logger, $config, $translator)
1 www 70
    {
16769 efrain 71
        $this->adapter      = $adapter;
72
        $this->cache        = $cache;
73
        $this->logger       = $logger;
74
        $this->config       = $config;
75
        $this->translator   = $translator;
1 www 76
    }
77
 
78
    /**
79
     *
17178 stevensc 80
     * Generación del listado de tópicos
1 www 81
     * {@inheritDoc}
82
     * @see \Laminas\Mvc\Controller\AbstractActionController::indexAction()
17178 stevensc 83
     * @return JsonModel
1 www 84
     */
85
    public function indexAction()
86
    {
17178 stevensc 87
        try {
88
            $request = $this->getRequest();
89
 
90
            $currentUserPlugin = $this->plugin('currentUserPlugin');
91
            $currentCompany = $currentUserPlugin->getCompany();
92
            $currentUser    = $currentUserPlugin->getUser();
1 www 93
 
17178 stevensc 94
            if (!$request->isGet()) {
95
                return $this->createErrorResponse('ERROR_METHOD_NOT_ALLOWED');
96
            }
97
 
98
            if(!$currentCompany) {
99
                return $this->createErrorResponse('ERROR_COMPANY_NOT_FOUND');
100
            }
101
 
102
            if(!$currentUser) {
103
                return $this->createErrorResponse('ERROR_USER_NOT_FOUND');
104
            }
1 www 105
 
17178 stevensc 106
            if($this->isJsonRequest($request)) {
107
                return $this->handleJsonRequest($currentUser, $currentCompany);
108
            }
109
 
110
            return $this->handleHtmlRequest($currentCompany);
111
        } catch (\Exception $e) {
112
            $this->logger->err('Error in indexAction: ' . $e->getMessage());
113
            return $this->createErrorResponse('ERROR_INTERNAL_SERVER_ERROR');
114
        }
115
    }
116
 
117
    /**
118
     *
119
     * Agregar un tópico
120
     * {@inheritDoc}
121
     * @see \Laminas\Mvc\Controller\AbstractActionController::addAction()
122
     * @return JsonModel
123
     */
124
    public function addAction()
125
    {
126
        try {
127
            $request    = $this->getRequest();
128
 
129
            $currentUserPlugin  = $this->plugin('currentUserPlugin');
130
            $currentCompany     = $currentUserPlugin->getCompany();
131
            $currentUser        = $currentUserPlugin->getUser();
132
 
133
            if(!$currentCompany) {
134
                return $this->createErrorResponse('ERROR_COMPANY_NOT_FOUND');
135
            }
136
 
137
            if(!$currentUser) {
138
                return $this->createErrorResponse('ERROR_USER_NOT_FOUND');
139
            }
140
 
141
            if(!$request->isPost() && !$request->isGet()) {
142
                return $this->createErrorResponse('ERROR_METHOD_NOT_ALLOWED');
143
            }
144
 
145
            if($request->isGet()) {
146
                $capsuleMapper = MicrolearningCapsuleMapper::getInstance($this->adapter);
147
                $records =  $capsuleMapper->fetchAllByCompanyId($currentCompany->id);
1 www 148
 
17178 stevensc 149
                $capsules = [];
150
 
151
                foreach($records as $record) {
152
                    array_push($capsules, [
17215 stevensc 153
                        'uuid' => $record->uuid,
17178 stevensc 154
                        'name' => $record->name,
155
                    ]);
1 www 156
                }
17178 stevensc 157
 
158
                return new JsonModel([
159
                    'success' => true,
160
                    'data' => ['capsules' => $capsules]
161
                ]);
1 www 162
            }
17178 stevensc 163
 
164
            if($request->isPost()) {
165
                $form = new TopicAddForm($this->adapter, $currentCompany->id);
166
                $dataPost = array_merge($request->getPost()->toArray(), $request->getFiles()->toArray());
1 www 167
 
17178 stevensc 168
                $form->setData($dataPost);
1 www 169
 
17178 stevensc 170
                if(!$form->isValid()) {
171
                    $messages = [];
172
                    $form_messages = (array) $form->getMessages();
173
 
174
                    foreach($form_messages  as $fieldname => $field_messages)
175
                    {
176
                        $messages[$fieldname] = array_values($field_messages);
177
                    }
178
 
179
                    return new JsonModel([
180
                        'success'   => false,
181
                        'data'   => $messages
182
                    ]);
1 www 183
                }
184
 
17178 stevensc 185
                $dataPost = (array) $form->getData();
186
 
187
                $topic = new MicrolearningTopic();
188
                $topic->company_id = $currentCompany->id;
189
                $topic->image = '';
190
                $topic->marketplace = '';
17216 stevensc 191
 
17222 stevensc 192
                unset($dataPost['capsule_uuid']);
193
 
194
                 // Create capsule relations
195
                 $capsuleUuids = isset($dataPost['capsule_uuid']) ? $dataPost['capsule_uuid'] : [];
196
                 if (!is_array($capsuleUuids)) {
197
                     $capsuleUuids = [$capsuleUuids];
198
                 }
199
 
200
                $hydrator = new HydratorObjectPropertyHydrator();
201
                $hydrator->hydrate($dataPost, $topic);
202
 
203
 
17178 stevensc 204
                $topicMapper = MicrolearningTopicMapper::getInstance($this->adapter);
1 www 205
 
17216 stevensc 206
                // First insert the topic to get the ID and UUID
17178 stevensc 207
                if(!$topicMapper->insert($topic)) {
208
                    return $this->createErrorResponse($topicMapper->getError());
209
                }
1 www 210
 
17216 stevensc 211
                // Get the complete topic with ID and UUID
17178 stevensc 212
                $topic = $topicMapper->fetchOne($topic->id);
17002 efrain 213
 
17216 stevensc 214
                // Now process images with the proper UUID
17214 stevensc 215
                $imageResult = $this->processTopicImages($request, $topic);
216
                if (!$imageResult['success']) {
217
                    return $this->createErrorResponse($imageResult['error']);
17178 stevensc 218
                }
1 www 219
 
17216 stevensc 220
                // Update topic with image filenames if processed
221
                if (!empty($imageResult['image_filename']) || !empty($imageResult['marketplace_filename'])) {
222
                    if (!empty($imageResult['image_filename'])) {
223
                        $topic->image = $imageResult['image_filename'];
224
                    }
225
                    if (!empty($imageResult['marketplace_filename'])) {
226
                        $topic->marketplace = $imageResult['marketplace_filename'];
227
                    }
228
 
229
                    if(!$topicMapper->update($topic)) {
230
                        return $this->createErrorResponse($topicMapper->getError());
231
                    }
232
                }
17002 efrain 233
 
17216 stevensc 234
                // Create capsule relations
17222 stevensc 235
                $result = $this->updateTopicCapsuleRelations($topic, $capsuleUuids, $currentCompany->id);
17216 stevensc 236
                if (!$result['success']) {
237
                    return $this->createErrorResponse($result['error']);
17178 stevensc 238
                }
1 www 239
 
17178 stevensc 240
                $this->logger->info('Se agrego el tópico ' . $topic->name, ['user_id' => $currentUser->id, 'ip' => Functions::getUserIP()]);
1 www 241
 
242
                return new JsonModel([
17178 stevensc 243
                    'success'   => true,
244
                    'data'   => 'LABEL_RECORD_ADDED'
1 www 245
                ]);
246
            }
17178 stevensc 247
        } catch (\Exception $e) {
248
            $this->logger->err('Error in addAction: ' . $e->getMessage());
249
            return $this->createErrorResponse('ERROR_INTERNAL_SERVER_ERROR');
1 www 250
        }
251
    }
17178 stevensc 252
 
253
    /**
254
     *
255
     * Borrar un tópico
256
     * {@inheritDoc}
257
     * @see \Laminas\Mvc\Controller\AbstractActionController::deleteAction()
258
     * @return JsonModel
259
     */
260
    public function deleteAction()
261
    {
262
        try {
263
            $request = $this->getRequest();
1 www 264
 
17178 stevensc 265
            $currentUserPlugin  = $this->plugin('currentUserPlugin');
266
            $currentCompany     = $currentUserPlugin->getCompany();
267
            $currentUser        = $currentUserPlugin->getUser();
268
 
269
            $id   = $this->params()->fromRoute('id');
270
 
271
            if(!$currentCompany) {
272
                return $this->createErrorResponse('ERROR_COMPANY_NOT_FOUND');
273
            }
274
 
275
            if(!$currentUser) {
276
                return $this->createErrorResponse('ERROR_USER_NOT_FOUND');
277
            }
278
 
279
            if(!$request->isPost()) {
280
                return $this->createErrorResponse('ERROR_METHOD_NOT_ALLOWED');
281
            }
282
 
283
            $topicMapper = MicrolearningTopicMapper::getInstance($this->adapter);
284
            $topic = $topicMapper->fetchOneByUuid($id);
1 www 285
 
17178 stevensc 286
            if(!$topic) {
287
                return $this->createErrorResponse('ERROR_TOPIC_NOT_FOUND');
288
            }
289
 
290
            if($topic->company_id != $currentCompany->id) {
291
                return $this->createErrorResponse('ERROR_UNAUTHORIZED');
292
            }
16943 efrain 293
 
17178 stevensc 294
            // Eliminar las relaciones con cápsulas primero
295
            $topicCapsuleMapper = MicrolearningTopicCapsuleMapper::getInstance($this->adapter);
296
 
297
            if(!$topicCapsuleMapper->deleteByTopicId($topic->id)) {
298
                return $this->createErrorResponse($topicCapsuleMapper->getError());
299
            }
17127 stevensc 300
 
17178 stevensc 301
            // Eliminar el progreso de los usuarios
302
            $userProgressMapper = MicrolearningUserProgressMapper::getInstance($this->adapter);
1 www 303
 
17178 stevensc 304
            if(!$userProgressMapper->deleteAllTopicProgressByTopicId($topic->id)) {
305
                return $this->createErrorResponse($userProgressMapper->getError());
17133 stevensc 306
            }
17127 stevensc 307
 
17178 stevensc 308
            // Eliminar archivos de almacenamiento
309
            $storage = Storage::getInstance($this->config, $this->adapter);
310
            $target_path = $storage->getPathMicrolearningTopic();
311
 
312
            if($topic->image) {
313
                if(!$storage->deleteFile($target_path, $topic->uuid, $topic->image)) {
314
                    return $this->createErrorResponse('ERROR_DELETING_FILE');
315
                }
316
            }
17127 stevensc 317
 
17178 stevensc 318
            if(!$topicMapper->delete($topic)) {
319
                return $this->createErrorResponse($topicMapper->getError());
17133 stevensc 320
            }
17127 stevensc 321
 
17178 stevensc 322
            if($topic->marketplace) {
323
                if(!$storage->deleteFile($target_path, $topic->uuid, $topic->marketplace)) {
324
                    return $this->createErrorResponse('ERROR_DELETING_FILE');
325
                }
326
            }
327
 
328
            // Registrar la acción en el log
329
            $this->logger->info('Se borro el tópico : ' . $topic->name, [
330
            'user_id' => $currentUser->id,
331
            'ip' => Functions::getUserIP()
332
            ]);
333
 
334
            return new JsonModel([
17133 stevensc 335
                'success' => true,
17178 stevensc 336
                'data' => 'LABEL_RECORD_DELETED'
337
            ]);
338
        } catch (\Exception $e) {
339
            $this->logger->err('Error in deleteAction: ' . $e->getMessage());
340
            return $this->createErrorResponse('ERROR_INTERNAL_SERVER_ERROR');
17133 stevensc 341
        }
17178 stevensc 342
    }
343
 
344
    /**
345
     *
346
     * Editar un tópico
347
     * {@inheritDoc}
348
     * @see \Laminas\Mvc\Controller\AbstractActionController::editAction()
349
     * @return JsonModel
350
     */
351
    public function editAction()
352
    {
353
        try {
354
            $request = $this->getRequest();
17127 stevensc 355
 
17178 stevensc 356
            $currentUserPlugin  = $this->plugin('currentUserPlugin');
357
            $currentCompany     = $currentUserPlugin->getCompany();
358
            $currentUser        = $currentUserPlugin->getUser();
17133 stevensc 359
 
17178 stevensc 360
            $id   = $this->params()->fromRoute('id');
17133 stevensc 361
 
17178 stevensc 362
            if(!$currentCompany) {
363
                return $this->createErrorResponse('ERROR_COMPANY_NOT_FOUND');
364
            }
365
 
366
            if(!$currentUser) {
367
                return $this->createErrorResponse('ERROR_USER_NOT_FOUND');
368
            }
369
 
370
            if(!$request->isPost() && !$request->isGet()) {
371
                return $this->createErrorResponse('ERROR_METHOD_NOT_ALLOWED');
372
            }
373
 
374
            if($request->isGet()) {
375
                $topicMapper = MicrolearningTopicMapper::getInstance($this->adapter);
376
                $topic = $topicMapper->fetchOneByUuid($id);
377
 
378
                if(!$topic) {
379
                    return $this->createErrorResponse('ERROR_TOPIC_NOT_FOUND');
1 www 380
                }
17178 stevensc 381
 
382
                if($topic->company_id != $currentCompany->id) {
383
                    return $this->createErrorResponse('ERROR_UNAUTHORIZED');
384
                }
1 www 385
 
17178 stevensc 386
                $capsuleMapper = MicrolearningCapsuleMapper::getInstance($this->adapter);
387
                $records =  $capsuleMapper->fetchAllByCompanyId($currentCompany->id);
388
 
389
                $capsules = [];
17214 stevensc 390
                $topicCapsuleMapper = MicrolearningTopicCapsuleMapper::getInstance($this->adapter);
17133 stevensc 391
 
17178 stevensc 392
                foreach($records as $record) {
17211 stevensc 393
                    $topicCapsule = $topicCapsuleMapper->fetchOneByTopicIdAndCapsuleId($topic->id, $record->id);
394
 
395
                    $selected = $topicCapsule ? true : false;
396
 
17178 stevensc 397
                    array_push($capsules, [
17215 stevensc 398
                        'uuid' => $record->uuid,
17178 stevensc 399
                        'name' => $record->name,
17211 stevensc 400
                        'selected' => $selected
17178 stevensc 401
                    ]);
402
                }
17133 stevensc 403
 
17178 stevensc 404
                $storage = Storage::getInstance($this->config, $this->adapter);
405
                $path = $storage->getPathMicrolearningTopic();
406
 
17133 stevensc 407
                $data = [
17178 stevensc 408
                    'success' => true,
409
                    'data' => [
410
                        'capsules' => $capsules,
411
                        'name' => $topic->name,
412
                        'description' => $topic->description,
413
                        'order' => $topic->order,
414
                        'status' => $topic->status,
415
                        'privacy' => $topic->privacy,
416
                        'type' => $topic->type,
417
                        'cost' => $topic->cost,
418
                        'image'=> $storage->getGenericImage($path, $topic->uuid, $topic->image),
419
                        'marketplace'=> $storage->getGenericImage($path, $topic->uuid, $topic->marketplace)
420
                    ]
17133 stevensc 421
                ];
17178 stevensc 422
 
17133 stevensc 423
                return new JsonModel($data);
424
            }
425
 
17178 stevensc 426
            if($request->isPost()) {
427
                $form = new  TopicEditForm($this->adapter, $currentCompany->id, $currentCompany->internal);
428
                $dataPost = array_merge($request->getPost()->toArray(), $request->getFiles()->toArray());
17133 stevensc 429
 
17178 stevensc 430
                $form->setData($dataPost);
431
 
432
                if(!$form->isValid()) {
433
                    $messages = [];
434
                    $form_messages = (array) $form->getMessages();
435
                    foreach($form_messages  as $fieldname => $field_messages)
436
                    {
437
 
438
                        $messages[$fieldname] = array_values($field_messages);
439
                    }
440
 
441
                    return new JsonModel([
442
                        'success'   => false,
443
                        'data'   => $messages
444
                    ]);
17133 stevensc 445
                }
17217 stevensc 446
 
17178 stevensc 447
                $topicMapper = MicrolearningTopicMapper::getInstance($this->adapter);
448
                $topic = $topicMapper->fetchOneByUuid($id);
17217 stevensc 449
 
17178 stevensc 450
                if(!$topic) {
451
                    return $this->createErrorResponse('ERROR_TOPIC_NOT_FOUND');
452
                }
17217 stevensc 453
 
17178 stevensc 454
                if($topic->company_id != $currentCompany->id) {
455
                    return $this->createErrorResponse('ERROR_UNAUTHORIZED');
456
                }
17216 stevensc 457
 
17217 stevensc 458
                $dataPost = (array) $form->getData();
17214 stevensc 459
 
17222 stevensc 460
                // Extract capsule_uuid for separate handling and remove from hydration data
461
                $capsuleUuids = isset($dataPost['capsule_uuid']) ? $dataPost['capsule_uuid'] : [];
462
                if (!is_array($capsuleUuids)) {
463
                    $capsuleUuids = [$capsuleUuids];
464
                }
465
                unset($dataPost['capsule_uuid']); // Remove to prevent dynamic property creation
466
 
17219 stevensc 467
                $hydrator = new ObjectPropertyHydrator();
468
                $hydrator->hydrate($dataPost, $topic);
469
 
17216 stevensc 470
                // Update basic topic data first
17178 stevensc 471
                if(!$topicMapper->update($topic)) {
472
                    return $this->createErrorResponse($topicMapper->getError());
473
                }
17214 stevensc 474
 
475
                // Process images if uploaded
476
                $imageResult = $this->processTopicImages($request, $topic);
477
                if (!$imageResult['success']) {
478
                    return $this->createErrorResponse($imageResult['error']);
17178 stevensc 479
                }
480
 
17214 stevensc 481
                // Update topic with new image filenames if they were processed
482
                if (!empty($imageResult['image_filename']) || !empty($imageResult['marketplace_filename'])) {
483
                    if (!empty($imageResult['image_filename'])) {
484
                        $topic->image = $imageResult['image_filename'];
17178 stevensc 485
                    }
17214 stevensc 486
                    if (!empty($imageResult['marketplace_filename'])) {
487
                        $topic->marketplace = $imageResult['marketplace_filename'];
17178 stevensc 488
                    }
17214 stevensc 489
 
490
                    if(!$topicMapper->update($topic)) {
491
                        return $this->createErrorResponse($topicMapper->getError());
492
                    }
17178 stevensc 493
                }
17216 stevensc 494
 
495
                // Update capsule relations
17222 stevensc 496
                $result = $this->updateTopicCapsuleRelations($topic, $capsuleUuids, $currentCompany->id);
17216 stevensc 497
                if (!$result['success']) {
498
                    return $this->createErrorResponse($result['error']);
499
                }
17178 stevensc 500
 
501
                $this->logger->info('Se edito el tópico ' . $topic->name, ['user_id' => $currentUser->id, 'ip' => Functions::getUserIP()]);
502
 
17133 stevensc 503
                return new JsonModel([
17178 stevensc 504
                    'success'   => true,
505
                    'data'   => 'LABEL_RECORD_UPDATED'
17093 stevensc 506
                ]);
507
            }
17178 stevensc 508
        } catch (\Exception $e) {
509
            $this->logger->err('Error in editAction: ' . $e->getMessage());
510
            return $this->createErrorResponse('ERROR_INTERNAL_SERVER_ERROR');
17093 stevensc 511
        }
1 www 512
    }
17178 stevensc 513
 
17185 stevensc 514
    /**
515
     *
516
     * Obtener los usuarios de un tópico
517
     * {@inheritDoc}
518
     * @see \Laminas\Mvc\Controller\AbstractActionController::usersAction()
519
     * @return JsonModel
520
     */
521
    public function usersAction()
522
    {
523
        try {
524
            $request = $this->getRequest();
525
 
526
            $currentUserPlugin = $this->plugin('currentUserPlugin');
527
            $currentUser    = $currentUserPlugin->getUser();
528
            $currentCompany = $currentUserPlugin->getCompany();
529
 
530
            if(!$currentCompany) {
531
                return $this->createErrorResponse('ERROR_COMPANY_NOT_FOUND');
532
            }
533
 
534
            if(!$currentUser) {
535
                return $this->createErrorResponse('ERROR_USER_NOT_FOUND');
536
            }
537
 
538
            if(!$request->isGet()) {
539
                return $this->createErrorResponse('ERROR_METHOD_NOT_ALLOWED');
540
            }
541
 
542
            $topic_uuid = $this->params()->fromRoute('topic_uuid');
543
            $type = $this->params()->fromRoute('type');
544
 
545
            $topicMapper = MicrolearningTopicMapper::getInstance($this->adapter);
546
            $topic = $topicMapper->fetchOneByUuid($topic_uuid);
547
            if(!$topic) {
548
                $this->logger->err('Error in usersAction: ' . $topic_uuid);
549
                return $this->createErrorResponse('ERROR_TOPIC_NOT_FOUND');
550
            }
551
 
552
            if($topic->company_id != $currentCompany->id) {
553
                $this->logger->err('Error in usersAction: ' . $topic_uuid);
554
                return $this->createErrorResponse('ERROR_UNAUTHORIZED');
555
            }
556
 
557
            $queryMapper = QueryMapper::getInstance($this->adapter);
558
            $sql = $queryMapper->getSql();
559
            $select = $sql->select();
560
            $select->columns(['access', 'paid_from', 'paid_to', 'added_on']);
561
            $select->from(['tb1' => MicrolearningTopicUserMapper::_TABLE] );
562
            $select->join(['tb2' => UserMapper::_TABLE], 'tb1.user_id = tb2.id', ['uuid', 'first_name', 'last_name', 'email']);
563
            $select->where->equalTo('tb1.company_id', $topic->company_id);
564
            $select->where->equalTo('tb1.topic_id', $topic->id);
565
 
566
            if($type == 'active') {
567
                $now = date('Y-m-d H:i:s');
568
                $select->where->nest->equalTo('access', MicrolearningTopicUser::ACCESS_UNLIMITED)->or->nest()
569
                ->equalTo('access', MicrolearningTopicUser::ACCESS_PAY_PERIOD)
570
                ->and->lessThanOrEqualTo('paid_from', $now)->and->greaterThanOrEqualTo('paid_to', $now )->unnest()->unnest();
571
 
572
            }
573
 
574
            $select->order(['first_name', 'last_name', 'email']);
575
            $records  = $queryMapper->fetchAll($select);
576
 
577
            $items = [];
578
 
579
            foreach($records as $record)
580
            {
581
                switch($record['access'])
582
                {
583
                    case MicrolearningTopicUser::ACCESS_UNLIMITED :
584
                        $details['access'] = 'LABEL_UNLIMIT';
585
                        break;
586
 
587
                    case MicrolearningTopicUser::ACCESS_REVOKE :
588
                        $details['access'] = 'LABEL_REVOKED';
589
                        break;
590
 
591
                    case MicrolearningTopicUser::ACCESS_PAY_PERIOD :
592
                        $dt_paid_from = \DateTime::createFromFormat('Y-m-d', $record['paid_from']);
593
                        $dt_paid_to = \DateTime::createFromFormat('Y-m-d', $record['paid_to']);
594
 
595
                        $details['access'] = 'LABEL_PAY_PERIOD';
596
                        $details['paid_from'] = $dt_paid_from->format('d/m/Y');
597
                        $details['paid_to'] = $dt_paid_to->format('d/m/Y');
598
                        break;
599
 
600
                    case MicrolearningTopicUser::ACCESS_SUPENDED :
601
                        $dt_paid_from = \DateTime::createFromFormat('Y-m-d', $record['paid_from']);
602
                        $dt_paid_to = \DateTime::createFromFormat('Y-m-d', $record['paid_to']);
603
 
604
                        $details['access'] = 'LABEL_SUSPENDED';
605
                        $details['paid_from'] = $dt_paid_from->format('d/m/Y');
606
                        $details['paid_to'] = $dt_paid_to->format('d/m/Y');
607
                        break;
608
 
609
                    case MicrolearningTopicUser::ACCESS_CANCELLED :
610
                        $dt_paid_from = \DateTime::createFromFormat('Y-m-d', $record['paid_from']);
611
                        $dt_paid_to = \DateTime::createFromFormat('Y-m-d', $record['paid_to']);
612
 
613
                        $details['access'] = 'LABEL_CANCELLED';
614
                        $details['paid_from'] = $dt_paid_from->format('d/m/Y');
615
                        $details['paid_to'] = $dt_paid_to->format('d/m/Y');
616
                        break;
617
                }
618
 
619
 
620
                $item = [
621
                    'first_name' => $record['first_name'],
622
                    'last_name' => $record['last_name'],
623
                    'email' => $record['email'],
624
                    'details' => $details,
625
                ];
626
 
627
                array_push($items, $item);
628
            }
629
 
630
            return new JsonModel([
631
                'success' => true,
632
                'data' => [
633
                    'topic' => $topic->name,
634
                    'items' => $items,
635
                ]
636
            ]);
637
        } catch (\Exception $e) {
638
            $this->logger->err('Error in usersAction: ' . $e->getMessage());
639
            return $this->createErrorResponse('ERROR_INTERNAL_SERVER_ERROR');
640
        }
641
    }
642
 
17178 stevensc 643
     /**
644
     * Check if request is JSON
645
     * @param \Laminas\Http\Request $request
646
     * @return bool
1 www 647
     */
17178 stevensc 648
    private function isJsonRequest($request)
1 www 649
    {
17178 stevensc 650
        $headers = $request->getHeaders();
651
        if (!$headers->has('Accept')) {
652
            return false;
17133 stevensc 653
        }
654
 
17178 stevensc 655
        $accept = $headers->get('Accept');
656
        $prioritized = $accept->getPrioritized();
17133 stevensc 657
 
17178 stevensc 658
        foreach ($prioritized as $value) {
659
            if (strpos(trim($value->getRaw()), 'json') !== false) {
660
                return true;
661
            }
1 www 662
        }
663
 
17178 stevensc 664
        return false;
665
    }
1 www 666
 
17178 stevensc 667
    /**
668
     * Handle JSON request for datatable
669
     * @param \LeadersLinked\Model\User $currentUser
670
     * @param \LeadersLinked\Model\Company $currentCompany
671
     * @return \Laminas\View\Model\JsonModel
672
     */
673
    private function handleJsonRequest($currentUser, $currentCompany)
674
    {
675
        try {
676
            $search = $this->params()->fromQuery('search', []);
677
            $search = empty($search['value']) ? '' : Functions::sanitizeFilterString($search['value']);
678
 
679
            $recordsPerPage = intval($this->params()->fromQuery('length', 10), 10);
680
            $page = (intval($this->params()->fromQuery('start', 1), 10) / $recordsPerPage) + 1;
681
 
682
            $order = $this->params()->fromQuery('order', []);
683
            $orderField = empty($order[0]['column']) ? 99 : intval($order[0]['column'], 10);
684
            $orderDirection = empty($order[0]['dir']) ? 'ASC' : strtoupper(Functions::sanitizeFilterString($order[0]['dir']));
685
 
686
            $fields = ['name'];
687
            $orderField = isset($fields[$orderField]) ? $fields[$orderField] : 'name';
688
 
689
            if (!in_array($orderDirection, ['ASC', 'DESC'])) {
690
                $orderDirection = 'ASC';
691
            }
692
 
693
            $acl = $this->getEvent()->getViewModel()->getVariable('acl');
694
            $permissions = $this->getUserPermissions($acl, $currentUser);
695
 
696
            $topicMapper = MicrolearningTopicMapper::getInstance($this->adapter);
697
            $paginator = $topicMapper->fetchAllDataTableByCompanyId(
698
                $currentCompany->id,
699
                $search,
700
                $page,
701
                $recordsPerPage,
702
                $orderField,
703
                $orderDirection
704
            );
705
 
706
            $items = $this->prepareTopicItems($paginator->getCurrentItems(), $currentCompany, $permissions);
707
 
708
            $response = [
709
                'success' => true,
710
                'data' => [
711
                    'link_add' => $permissions['allowAdd'] ? $this->url()->fromRoute('microlearning/content/topics/add') : '',
712
                    'items' => $items,
713
                    'total' => $paginator->getTotalItemCount(),
714
                ]
715
            ];
716
 
717
            return new JsonModel($response);
718
 
719
        } catch (\Exception $e) {
720
            $this->logger->err('Error in handleJsonRequest: ' . $e->getMessage());
721
            return $this->createErrorResponse('ERROR_INTERNAL_SERVER_ERROR');
17133 stevensc 722
        }
17178 stevensc 723
    }
17133 stevensc 724
 
17178 stevensc 725
    /**
726
     * Handle HTML request for view
727
     * @param \LeadersLinked\Model\Company $currentCompany
728
     * @return \Laminas\View\Model\ViewModel
729
     */
730
    private function handleHtmlRequest($currentCompany)
731
    {
732
        $imageSize = $this->config['leaderslinked.image_sizes.microlearning_image_upload'];
733
        $marketplaceSize = $this->config['leaderslinked.image_sizes.marketplace'];
1 www 734
 
17178 stevensc 735
        $formAdd = new TopicAddForm($this->adapter, $currentCompany->id, $currentCompany->internal);
736
        $formEdit = new TopicEditForm($this->adapter, $currentCompany->id, $currentCompany->internal);
17002 efrain 737
 
17178 stevensc 738
        $this->layout()->setTemplate('layout/layout-backend.phtml');
739
        $viewModel = new ViewModel();
740
        $viewModel->setTemplate('leaders-linked/microlearning-topics/index.phtml');
741
        $viewModel->setVariables([
742
            'formAdd' => $formAdd,
743
            'formEdit' => $formEdit,
744
            'company_uuid' => $currentCompany->uuid,
745
            'image_size' => $imageSize,
746
            'marketplace_size' => $marketplaceSize,
17133 stevensc 747
        ]);
1 www 748
 
17178 stevensc 749
        return $viewModel;
750
    }
751
 
752
    /**
753
     * Get user permissions for topic actions
754
     * @param \Laminas\Permissions\Acl\Acl $acl
755
     * @param \LeadersLinked\Model\User $currentUser
756
     * @return array
757
     */
758
    private function getUserPermissions($acl, $currentUser)
759
    {
760
        return [
761
            'allowAdd' => $acl->isAllowed($currentUser->usertype_id, 'microlearning/content/topics/add'),
762
            'allowEdit' => $acl->isAllowed($currentUser->usertype_id, 'microlearning/content/topics/edit'),
763
            'allowDelete' => $acl->isAllowed($currentUser->usertype_id, 'microlearning/content/topics/delete'),
764
            'allowUsers' => $acl->isAllowed($currentUser->usertype_id, 'microlearning/content/topics/users')
765
        ];
766
    }
767
 
768
    /**
769
     * Create error response
770
     * @param string $message
771
     * @return \Laminas\View\Model\JsonModel
772
     */
773
    private function createErrorResponse($message)
774
    {
17133 stevensc 775
        return new JsonModel([
17178 stevensc 776
            'success' => false,
777
            'data' => $message
17133 stevensc 778
        ]);
1 www 779
    }
780
 
17178 stevensc 781
     /**
782
     * Prepare topic items for datatable
783
     * @param array $records
784
     * @param \LeadersLinked\Model\Company $currentCompany
785
     * @param array $permissions
786
     * @return array
787
     */
788
    private function prepareTopicItems($records, $currentCompany, $permissions)
1 www 789
    {
17178 stevensc 790
        $items = [];
791
        $microlearningTopicUserMapper = MicrolearningTopicUserMapper::getInstance($this->adapter);
792
        $storage = Storage::getInstance($this->config, $this->adapter);
793
        $path = $storage->getPathMicrolearningTopic();
17109 stevensc 794
 
17178 stevensc 795
        foreach ($records as $record) {
796
            $totalUsers = $microlearningTopicUserMapper->fetchCountUsersByCompanyIdAndTopicId($currentCompany->id, $record->id);
797
            $totalUsersActive = $microlearningTopicUserMapper->fetchCountUsersActiveByCompanyIdAndTopicId($currentCompany->id, $record->id);
798
 
799
            $status = $this->getTopicStatus($record->status);
800
            $privacy = $this->getTopicPrivacy($record->privacy);
801
            $type = $this->getTopicType($record->type);
802
 
803
            $items[] = [
804
                'name' => $record->name,
805
                'details' => [
806
                    'status' => $status,
807
                    'privacy' => $privacy,
808
                    'type' => $type,
809
                    'cost' => $record->cost,
810
                    'total_users' => $totalUsers,
811
                    'total_users_active' => $totalUsersActive,
812
                ],
813
                'images' => [
814
                    'image' => $storage->getGenericImage($path, $record->uuid, $record->image),
17195 stevensc 815
                    'marketplace' => $storage->getGenericImage($path, $record->uuid, $record->marketplace)
17178 stevensc 816
                ],
817
                'actions' => $this->prepareTopicActions($record, $permissions, $totalUsers, $totalUsersActive)
818
            ];
1 www 819
        }
17178 stevensc 820
 
821
        return $items;
822
    }
823
 
824
        /**
825
     * Get topic status label
826
     * @param int $status
827
     * @return string
828
     */
829
    private function getTopicStatus($status)
830
    {
831
        switch ($status) {
832
            case MicrolearningTopic::STATUS_ACTIVE:
833
                return 'LABEL_ACTIVE';
834
            case MicrolearningTopic::STATUS_INACTIVE:
835
                return 'LABEL_INACTIVE';
836
            default:
837
                return '';
1 www 838
        }
17178 stevensc 839
    }
840
 
841
    /**
842
     * Get topic privacy label
843
     * @param int $privacy
844
     * @return string
845
     */
846
    private function getTopicPrivacy($privacy)
847
    {
848
        switch ($privacy) {
849
            case MicrolearningTopic::PRIVACY_PUBLIC:
850
                return 'LABEL_PUBLIC';
851
            case MicrolearningTopic::PRIVACY_PRIVATE:
852
                return 'LABEL_PRIVATE';
853
            default:
854
                return '';
1 www 855
        }
856
    }
17178 stevensc 857
 
858
    /**
859
     * Get topic type label
860
     * @param int $type
861
     * @return string
862
     */
863
    private function getTopicType($type)
864
    {
865
        switch ($type) {
866
            case MicrolearningTopic::TYPE_FREE:
867
                return 'LABEL_FREE';
868
            case MicrolearningTopic::TYPE_PRIVATE:
869
                return 'LABEL_PRIVATE';
870
            case MicrolearningTopic::TYPE_SELLING:
871
                return 'LABEL_SELLING';
872
            default:
873
                return '';
874
        }
875
    }
876
 
877
     /**
878
     * Prepare topic actions
879
     * @param \LeadersLinked\Model\MicrolearningTopic $record
880
     * @param array $permissions
881
     * @param int $totalUsers
882
     * @param int $totalUsersActive
883
     * @return array
884
     */
885
    private function prepareTopicActions($record, $permissions, $totalUsers, $totalUsersActive)
886
    {
17188 stevensc 887
        $editDeleteParams = ['id' => $record->uuid];
17178 stevensc 888
 
889
        return [
17188 stevensc 890
            'link_edit' => $permissions['allowEdit'] ? $this->url()->fromRoute('microlearning/content/topics/edit', $editDeleteParams) : '',
891
            'link_delete' => $permissions['allowDelete'] ? $this->url()->fromRoute('microlearning/content/topics/delete', $editDeleteParams) : '',
17178 stevensc 892
            'link_total_users' => $permissions['allowUsers'] && $totalUsers ?
893
                $this->url()->fromRoute('microlearning/content/topics/users', [
894
                    'topic_uuid' => $record->uuid,
895
                    'type' => 'all'
896
                ]) : '',
897
            'link_total_users_actives' => $permissions['allowUsers'] && $totalUsersActive ?
898
                $this->url()->fromRoute('microlearning/content/topics/users', [
899
                    'topic_uuid' => $record->uuid,
900
                    'type' => 'active'
901
                ]) : ''
902
        ];
903
    }
17214 stevensc 904
 
905
    /**
906
     * Update topic capsule relations
907
     * @param \LeadersLinked\Model\MicrolearningTopic $topic
908
     * @param array $capsuleUuids
909
     * @param int $companyId
910
     * @return array
911
     */
912
    private function updateTopicCapsuleRelations($topic, $capsuleUuids, $companyId)
913
    {
914
        try {
915
            $topicCapsuleMapper = MicrolearningTopicCapsuleMapper::getInstance($this->adapter);
916
            $topicCapsuleMapper->deleteByTopicId($topic->id);
917
 
918
            $capsuleMapper = MicrolearningCapsuleMapper::getInstance($this->adapter);
919
            foreach ($capsuleUuids as $capsuleUuid) {
920
                $capsule = $capsuleMapper->fetchOneByUuid($capsuleUuid);
921
 
922
                if ($capsule) {
923
                    $topicCapsule = new MicrolearningTopicCapsule();
924
                    $topicCapsule->topic_id = $topic->id;
925
                    $topicCapsule->capsule_id = $capsule->id;
926
                    $topicCapsule->company_id = $companyId;
927
                    $topicCapsuleMapper->insert($topicCapsule);
928
                }
929
            }
930
 
931
            return ['success' => true];
932
        } catch (\Exception $e) {
933
            return ['success' => false, 'error' => $e->getMessage()];
934
        }
935
    }
936
 
937
    /**
938
     * Process topic images
939
     * @param \Laminas\Http\Request $request
940
     * @param \LeadersLinked\Model\MicrolearningTopic $topic
941
     * @return array
942
     */
943
    private function processTopicImages($request, $topic)
944
    {
945
        try {
946
            $storage = Storage::getInstance($this->config, $this->adapter);
947
            $target_path = $storage->getPathMicrolearningTopic();
948
            $storage->setFiles($request->getFiles()->toArray());
949
 
950
            $result = [
951
                'success' => true,
952
                'image_filename' => '',
953
                'marketplace_filename' => ''
954
            ];
955
 
956
            // Process main image if uploaded
17219 stevensc 957
            if ($storage->setCurrentFilename('image')) {
17214 stevensc 958
                $target_size = $this->config['leaderslinked.image_sizes.microlearning_image_size'];
959
                list($target_width, $target_height) = explode('x', $target_size);
960
 
961
                $image_source_filename = $storage->getTmpFilename();
962
                $image_filename = 'topic-' . uniqid() . '.png';
963
                $image_target_filename = $storage->composePathToFilename(
964
                    Storage::TYPE_MICROLEARNING_TOPIC,
965
                    $topic->uuid,
966
                    $image_filename
967
                );
968
 
969
                if (!$storage->uploadImageCrop($image_source_filename, $image_target_filename, $target_width, $target_height)) {
970
                    return ['success' => false, 'error' => 'ERROR_UPLOAD_IMAGE'];
971
                }
972
 
973
                // Delete old image if exists
974
                if ($topic->image) {
975
                    $storage->deleteFile($target_path, $topic->uuid, $topic->image);
976
                }
977
 
978
                $result['image_filename'] = $image_filename;
979
            }
980
 
981
            // Process marketplace image if uploaded
982
            if ($storage->setCurrentFilename('marketplace')) {
983
                $target_size = $this->config['leaderslinked.image_sizes.microlearning_image_size'];
984
                list($target_width, $target_height) = explode('x', $target_size);
985
 
986
                $marketplace_source_filename = $storage->getTmpFilename();
987
                $marketplace_filename = 'marketplace-' . uniqid() . '.png';
988
                $marketplace_target_filename = $storage->composePathToFilename(
989
                    Storage::TYPE_MICROLEARNING_TOPIC,
990
                    $topic->uuid,
991
                    $marketplace_filename
992
                );
993
 
994
                if (!$storage->uploadImageCrop($marketplace_source_filename, $marketplace_target_filename, $target_width, $target_height)) {
995
                    return ['success' => false, 'error' => 'ERROR_UPLOAD_IMAGE'];
996
                }
997
 
998
                // Delete old marketplace image if exists
999
                if ($topic->marketplace) {
1000
                    $storage->deleteFile($target_path, $topic->uuid, $topic->marketplace);
1001
                }
1002
 
1003
                $result['marketplace_filename'] = $marketplace_filename;
1004
            }
1005
 
1006
            return $result;
1007
        } catch (\Exception $e) {
1008
            return ['success' => false, 'error' => $e->getMessage()];
1009
        }
1010
    }
1 www 1011
}