Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
33.33% |
24 / 72 |
CRAP | |
38.11% |
117 / 307 |
Task | |
0.00% |
0 / 1 |
|
33.33% |
24 / 72 |
6000.12 | |
38.11% |
117 / 307 |
init | |
100.00% |
1 / 1 |
3 | |
100.00% |
9 / 9 |
|||
afterFind | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
updateState | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
scenarios | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
tableName | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
__get | |
0.00% |
0 / 1 |
2.15 | |
66.67% |
2 / 3 |
|||
__set | |
100.00% |
1 / 1 |
2 | |
100.00% |
4 / 4 |
|||
getContentName | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
getContentDescription | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
getIcon | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
rules | |
100.00% |
1 / 1 |
1 | |
100.00% |
4 / 4 |
|||
anonymous function | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
validateTaskList | |
0.00% |
0 / 1 |
3.07 | |
80.00% |
4 / 5 |
|||
attributeLabels | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 19 |
|||
getUrl | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
getList | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
findUnsorted | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
findUnsortedCompleted | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
findUserTasks | |
0.00% |
0 / 1 |
30 | |
0.00% |
0 / 12 |
|||
findPendingTasks | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 4 |
|||
findReadable | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 4 |
|||
beforeSave | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
beforeDelete | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 7 |
|||
afterSave | |
0.00% |
0 / 1 |
74.76 | |
19.23% |
5 / 26 |
|||
afterMove | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 5 |
|||
getTaskAssignedUsers | |
100.00% |
1 / 1 |
2 | |
100.00% |
5 / 5 |
|||
isTaskAssigned | |
0.00% |
0 / 1 |
4.05 | |
85.71% |
6 / 7 |
|||
addTaskAssigned | |
0.00% |
0 / 1 |
4.10 | |
81.82% |
9 / 11 |
|||
afterDelete | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 4 |
|||
getTaskUsers | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
getAssignedTaskUsers | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
hasTaskAssigned | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
getUsers | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
getTaskResponsible | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
hasTaskResponsible | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
getTaskResponsibleUsers | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
isTaskResponsible | |
0.00% |
0 / 1 |
4.25 | |
75.00% |
3 / 4 |
|||
isOwner | |
0.00% |
0 / 1 |
4.13 | |
80.00% |
4 / 5 |
|||
addTaskResponsible | |
0.00% |
0 / 1 |
4.10 | |
81.82% |
9 / 11 |
|||
isOverdue | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
getTaskReminder | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
getItems | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
hasItems | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
saveNewItems | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 6 |
|||
addItem | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 7 |
|||
setNewItems | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
setEditItems | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
confirm | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 6 |
|||
completeItems | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
getConfirmedCount | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
isPending | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
isInProgress | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
isPendingReview | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
isCompleted | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
canReview | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 1 |
|||
canEdit | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 5 |
|||
filterResponsibleAssigned | |
100.00% |
1 / 1 |
1 | |
100.00% |
5 / 5 |
|||
deleteOldNotifications | |
0.00% |
0 / 1 |
4.03 | |
87.50% |
7 / 8 |
|||
getTitle | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
getBadge | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 3 |
|||
getSearchAttributes | |
0.00% |
0 / 1 |
2.04 | |
77.78% |
7 / 9 |
|||
canProcess | |
0.00% |
0 / 1 |
5.05 | |
87.50% |
7 / 8 |
|||
canCheckItems | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 1 |
|||
canReviewTask | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
canResetTask | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 1 |
|||
canResortItems | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 1 |
|||
getPercent | |
0.00% |
0 / 1 |
110 | |
0.00% |
0 / 16 |
|||
getLabels | |
0.00% |
0 / 1 |
42 | |
0.00% |
0 / 17 |
|||
moveItemIndex | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
beforeRemoveUser | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 4 |
|||
removeUser | |
0.00% |
0 / 1 |
30 | |
0.00% |
0 / 9 |
|||
getColor | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 3 |
<?php | |
/** | |
* @link https://www.humhub.org/ | |
* @copyright Copyright (c) 2018 HumHub GmbH & Co. KG | |
* @license https://www.humhub.com/licences | |
* | |
*/ | |
namespace humhub\modules\tasks\models; | |
use humhub\modules\content\components\ContentContainerPermissionManager; | |
use humhub\modules\space\modules\manage\models\MembershipSearch; | |
use humhub\modules\tasks\helpers\TaskUrl; | |
use humhub\modules\tasks\permissions\CreateTask; | |
use humhub\modules\tasks\permissions\ProcessUnassignedTasks; | |
use humhub\modules\user\components\ActiveQueryUser; | |
use Yii; | |
use yii\db\ActiveQuery; | |
use yii\db\Expression; | |
use humhub\modules\notification\models\Notification; | |
use humhub\modules\tasks\models\checklist\TaskCheckList; | |
use humhub\modules\tasks\models\checklist\TaskItem; | |
use humhub\modules\tasks\models\lists\TaskList; | |
use humhub\modules\tasks\models\scheduling\TaskReminder; | |
use humhub\modules\tasks\models\scheduling\TaskScheduling; | |
use humhub\modules\tasks\models\state\TaskState; | |
use humhub\modules\tasks\models\user\TaskUser; | |
use humhub\libs\DbDateValidator; | |
use humhub\modules\content\components\ContentContainerActiveRecord; | |
use humhub\modules\content\components\ContentActiveRecord; | |
use humhub\modules\user\models\User; | |
use humhub\modules\search\interfaces\Searchable; | |
use humhub\widgets\Label; | |
use humhub\modules\tasks\widgets\WallEntry; | |
use humhub\modules\tasks\permissions\ManageTasks; | |
/** | |
* This is the model class for table "task". | |
* | |
* The followings are the available columns in table 'task': | |
* @property integer $id | |
* @property string $title | |
* @property string $color | |
* @property string $description | |
* @property integer $review | |
* @property integer $request_sent | |
* @property integer $scheduling | |
* @property integer $all_day | |
* @property string $start_datetime | |
* @property string $end_datetime | |
* @property integer $status | |
* @property integer $cal_mode | |
* @property integer $task_list_id | |
* @property string $time_zone The timeZone this entry was saved, note the dates itself are always saved in app timeZone | |
* | |
* @property TaskReminder[] $taskReminder | |
* @property TaskItem[] $items | |
* @property TaskList $list | |
* @property User[] $taskResponsibleUsers | |
* @property User[] $taskAssignedUsers | |
*/ | |
class Task extends ContentActiveRecord implements Searchable | |
{ | |
const SCENARIO_EDIT = 'edit'; | |
/** | |
* @inheritdocs | |
*/ | |
public $canMove = true; | |
/** | |
* @inheritdocs | |
*/ | |
public $moduleId = 'tasks'; | |
/** | |
* @inheritdocs | |
*/ | |
public $wallEntryClass = WallEntry::class; | |
public $assignedUsers; | |
public $responsibleUsers; | |
public $selectedReminders; | |
public $newItems; | |
public $editItems; | |
/** | |
* Status | |
*/ | |
const STATUS_PENDING = 1; | |
const STATUS_IN_PROGRESS = 2; | |
const STATUS_PENDING_REVIEW = 3; | |
const STATUS_COMPLETED = 5; | |
const STATUS_ALL = 4; | |
/** | |
* @deprecated | |
*/ | |
const STATUS_OPEN = 1; | |
/** | |
* @var array all given statuses as array | |
*/ | |
public static $statuses = [ | |
self::STATUS_PENDING, | |
self::STATUS_IN_PROGRESS, | |
self::STATUS_PENDING_REVIEW, | |
self::STATUS_COMPLETED | |
]; | |
/** | |
* User Types | |
*/ | |
const USER_ASSIGNED = 0; | |
const USER_RESPONSIBLE = 1; | |
/** | |
* @var TaskState | |
*/ | |
public $state; | |
/** | |
* @var TaskScheduling | |
*/ | |
public $schedule; | |
/** | |
* @var TaskCheckList | |
*/ | |
public $checklist; | |
public function init() | |
{ | |
$this->schedule = new TaskScheduling(['task' => $this]); | |
$this->checklist = new TaskCheckList(['task' => $this]); | |
if($this->status == null) { | |
$this->status = static::STATUS_PENDING; | |
} | |
$this->updateState(); | |
if(!$this->all_day) { | |
$this->all_day = 1; | |
} | |
parent::init(); | |
} | |
public function afterFind() | |
{ | |
$this->updateState(); | |
parent::afterFind(); | |
} | |
protected function updateState() | |
{ | |
$this->state = TaskState::getState($this); | |
} | |
public function scenarios() | |
{ | |
$scenarios = parent::scenarios(); | |
$scenarios[self::SCENARIO_EDIT] = $scenarios[self::SCENARIO_DEFAULT]; | |
return $scenarios; | |
} | |
/** | |
* @return string the associated database table name | |
*/ | |
public static function tableName() | |
{ | |
return 'task'; | |
} | |
/** | |
* @inheritdoc | |
*/ | |
public function __get($name) | |
{ | |
if ($name == 'deadline') { | |
return parent::__get('end_datetime'); | |
} | |
return parent::__get($name); | |
} | |
public function __set($name, $value) | |
{ | |
parent::__set($name,$value); | |
if($name == 'status') { | |
$this->updateState(); | |
} | |
} | |
/** | |
* @inheritdoc | |
*/ | |
public function getContentName() | |
{ | |
return Yii::t('TasksModule.base', 'Task'); | |
} | |
/** | |
* @inheritdoc | |
*/ | |
public function getContentDescription() | |
{ | |
return $this->title; | |
} | |
/** | |
* @inheritdoc | |
*/ | |
public function getIcon() | |
{ | |
return 'fa-tasks'; | |
} | |
/** | |
* @inheritdoc | |
*/ | |
public function rules() | |
{ | |
return [ | |
[['title'], 'required'], | |
[['color'], 'string', 'max' => 7], | |
[['start_datetime', 'end_datetime'], 'required', 'when' => function ($model) { | |
return $model->scheduling == 1; | |
}, 'whenClient' => "function (attribute, value) { | |
return $('#task-scheduling').val() == 1; | |
}"], | |
[['start_datetime'], 'default', 'value' => null], | |
[['end_datetime'], 'default', 'value' => null], | |
[['start_datetime'], DbDateValidator::class], | |
[['end_datetime'], DbDateValidator::class], | |
[['all_day', 'scheduling', 'review', 'request_sent'], 'integer'], | |
[['cal_mode'], 'in', 'range' => TaskScheduling::$calModes], | |
[['assignedUsers', 'description', 'responsibleUsers', 'selectedReminders'], 'safe'], | |
[['title'], 'string', 'max' => 255], | |
[['task_list_id'], 'validateTaskList'] | |
]; | |
} | |
public function validateTaskList($attribute, $params) | |
{ | |
if($this->task_list_id) { | |
$taskList = TaskList::findByContainer($this->content->container)->where(['id' => $this->task_list_id]); | |
if(!$taskList) { | |
$this->addError('task_list_id', Yii::t('TasksModule.base', 'Invalid task list selection.')); | |
} | |
} | |
} | |
/** | |
* @inheritdoc | |
*/ | |
public function attributeLabels() | |
{ | |
return [ | |
'id' => 'ID', | |
'title' => Yii::t('TasksModule.models_task', 'Title'), | |
'color' => Yii::t('TasksModule.models_task', 'Color'), | |
'description' => Yii::t('TasksModule.models_task', 'Description'), | |
'review' => Yii::t('TasksModule.models_task', 'Review by responsible user required'), | |
'request_sent' => Yii::t('TasksModule.models_task', 'Extend deadline request'), | |
'scheduling' => Yii::t('TasksModule.models_task', 'Scheduling'), | |
'all_day' => Yii::t('TasksModule.models_task', 'All Day'), | |
'start_datetime' => Yii::t('TasksModule.models_task', 'Start'), | |
'end_datetime' => Yii::t('TasksModule.models_task', 'End'), | |
'status' => Yii::t('TasksModule.models_task', 'Status'), | |
'cal_mode' => Yii::t('TasksModule.models_task', 'Add schedule to the space calendar'), | |
'parent_task_id' => Yii::t('TasksModule.models_task', 'Parent Task'), | |
'newItems' => Yii::t('TasksModule.models_task', 'Checklist Items'), | |
'editItems' => Yii::t('TasksModule.models_task', 'Checklist Items'), | |
'assignedUsers' => Yii::t('TasksModule.models_task', 'Assigned user(s)'), | |
'responsibleUsers' => Yii::t('TasksModule.models_task', 'Responsible user(s)'), | |
'selectedReminders' => Yii::t('TasksModule.models_task', 'Reminders'), | |
'task_list_id' => Yii::t('TasksModule.base', 'List'), | |
]; | |
} | |
/** | |
* @inheritdoc | |
*/ | |
public function getUrl() | |
{ | |
return TaskUrl::viewTask($this); | |
} | |
public function getList() | |
{ | |
return $this->hasOne(TaskList::class, ['id' => 'task_list_id']); | |
} | |
/** | |
* @param ContentContainerActiveRecord $contentContainer | |
* @return \humhub\modules\content\components\ActiveQueryContent | |
*/ | |
public static function findUnsorted(ContentContainerActiveRecord $contentContainer) | |
{ | |
return static::find()->contentContainer($contentContainer)->where('task_list_id IS NULL')->readable(); | |
} | |
/** | |
* @param ContentContainerActiveRecord $contentContainer | |
* @return \humhub\modules\content\components\ActiveQueryContent | |
*/ | |
public static function findUnsortedCompleted(ContentContainerActiveRecord $contentContainer) | |
{ | |
return static::findUnsorted($contentContainer)->andWhere(['task.status' => Task::STATUS_COMPLETED]); | |
} | |
/** | |
* @param User|null $user | |
* @param ContentActiveRecord|null $container | |
* @param int $limit | |
* @return array|Notification[]|Task[]|\yii\db\ActiveRecord[] | |
* @throws \Throwable | |
* @throws \yii\base\Exception | |
*/ | |
public static function findUserTasks(User $user = null, $container = null, $limit = 5) | |
{ | |
if (!$user && !Yii::$app->user->isGuest) { | |
$user = Yii::$app->user->getIdentity(); | |
} else if (!$user) { | |
return []; | |
} | |
$query = ($container) ? self::find()->contentContainer($container) : self::find(); | |
return $query | |
->leftJoin('task_user', 'task.id=task_user.task_id', []) | |
->where(['task_user.user_id' => $user->id]) | |
->andWhere(['!=', 'task.status', Task::STATUS_COMPLETED]) | |
->orderBy([new Expression('-task.end_datetime DESC')]) | |
->readable() | |
->limit($limit) | |
->all(); | |
} | |
public static function findPendingTasks(ContentContainerActiveRecord $container) | |
{ | |
return self::find() | |
->contentContainer($container) | |
//->orderBy([new Expression('-task.end_datetime DESC')]) | |
->readable() | |
->andWhere(['!=', 'task.status', Task::STATUS_COMPLETED]); | |
} | |
public static function findReadable(ContentContainerActiveRecord $container) | |
{ | |
return self::find() | |
->contentContainer($container) | |
->orderBy(['task.end_datetime' => SORT_DESC]) | |
->readable(); | |
} | |
/** | |
* @inheritdoc | |
*/ | |
public function beforeSave($insert) | |
{ | |
$this->schedule->beforeSave(); | |
return parent::beforeSave($insert); | |
} | |
/** | |
* @inheritdoc | |
*/ | |
public function beforeDelete() | |
{ | |
foreach (TaskItem::findAll(['task_id' => $this->id]) as $item) { | |
$item->delete(); | |
} | |
foreach (TaskUser::findAll(['task_id' => $this->id]) as $taskUser) { | |
$taskUser->delete(); | |
} | |
foreach (TaskReminder::findAll(['task_id' => $this->id]) as $taskReminder) { | |
$taskReminder->delete(); | |
} | |
return parent::beforeDelete(); | |
} | |
/** | |
* Saves new items (if set) and updates items given edititems (if set) | |
* | |
* @param boolean $insert | |
* @param array $changedAttributes | |
* @return boolean | |
*/ | |
public function afterSave($insert, $changedAttributes) | |
{ | |
parent::afterSave($insert, $changedAttributes); | |
if($this->scenario === self::SCENARIO_EDIT) { | |
$oldTaskUsers = $this->taskUsers; | |
TaskUser::deleteAll(['task_id' => $this->id]); | |
if (!empty($this->assignedUsers)) { | |
foreach ($this->assignedUsers as $guid) { | |
$user = User::findOne(['guid' => $guid]); | |
if(!$user) { | |
continue; | |
} | |
$oldAssigned = array_filter($oldTaskUsers, function($taskUser) use ($user) { | |
/** @var $taskUser TaskUser */ | |
return $taskUser->user_id === $user->id && $taskUser->user_type === Task::USER_ASSIGNED; | |
}); | |
$this->addTaskAssigned($guid, empty($oldAssigned)); | |
} | |
} | |
if (!empty($this->responsibleUsers)) { | |
foreach ($this->responsibleUsers as $guid) { | |
$user = User::findOne(['guid' => $guid]); | |
if(!$user) { | |
continue; | |
} | |
$oldResponsible = array_filter($oldTaskUsers, function($taskUser) use ($user) { | |
/** @var $taskUser TaskUser */ | |
return $taskUser->user_id === $user->id && $taskUser->user_type === Task::USER_RESPONSIBLE; | |
}); | |
$this->addTaskResponsible($guid, empty($oldResponsible)); | |
} | |
} | |
$this->checklist->afterSave($insert); | |
$this->schedule->afterSave($insert, $changedAttributes); | |
$this->saveNewItems(); | |
} | |
if($this->list) { | |
$this->list->setAttributes(['updated_at' => new Expression('NOW()')]); | |
} | |
} | |
public function afterMove(ContentContainerActiveRecord $container = null) | |
{ | |
foreach ($this->taskUsers as $taskUser) { | |
if(!$container->isMember($taskUser->user_id)) { | |
$taskUser->delete(); | |
} | |
} | |
$this->updateAttributes(['task_list_id' => null]); | |
} | |
/** | |
* Returns an ActiveQuery for all assigned user models of this task. | |
* | |
* @return \yii\db\ActiveQuery | |
*/ | |
public function getTaskAssignedUsers($filterOutResponsibleUsers = false) | |
{ | |
$query = $this->hasMany(User::class, ['id' => 'user_id'])->via('assignedTaskUsers'); | |
if($filterOutResponsibleUsers) { | |
$responsible = $this->getTaskResponsibleUsers()->select(['id']); | |
$query->where(['not in', 'user.id', $responsible]); | |
} | |
return $query; | |
} | |
public function isTaskAssigned($user = null) | |
{ | |
if (!$user && !Yii::$app->user->isGuest) { | |
$user = Yii::$app->user->getIdentity(); | |
} else if (!$user) { | |
return false; | |
} | |
$taskAssigned = array_filter($this->assignedTaskUsers, function (TaskUser $p) use ($user) { | |
return $p->user_id == $user->id; | |
}); | |
return !empty($taskAssigned); | |
} | |
public function addTaskAssigned($user, $sendNotification = true) | |
{ | |
$user = (is_string($user)) ? User::findOne(['guid' => $user]) : $user; | |
if (!$user) { | |
return false; | |
} | |
if (!$this->isTaskAssigned($user)) { | |
$taskAssigned = new TaskUser([ | |
'task_id' => $this->id, | |
'user_id' => $user->id, | |
'user_type' => self::USER_ASSIGNED, | |
'sendNotificationOnCreation' => $sendNotification, | |
]); | |
return $taskAssigned->save(); | |
} | |
return false; | |
} | |
/** | |
* @inheritdoc | |
*/ | |
public function afterDelete() | |
{ | |
if($this->list) { | |
$this->list->setAttributes(['updated_at' => new Expression('NOW()')]); | |
} | |
parent::afterDelete(); | |
} | |
// ########### handle assigned users ########### | |
public function getTaskUsers() | |
{ | |
return $this->hasMany(TaskUser::class, ['task_id' => 'id']); | |
} | |
/** | |
* Returns an ActiveQuery for all assigned task users of this task. | |
* | |
* @return \yii\db\ActiveQuery | |
*/ | |
public function getAssignedTaskUsers() | |
{ | |
return $this->getTaskUsers()->andOnCondition(['user_type' => self::USER_ASSIGNED]); | |
} | |
public function hasTaskAssigned() | |
{ | |
return !empty($this->assignedTaskUsers); | |
} | |
public function getUsers() | |
{ | |
return $this->hasMany(User::class, ['id' => 'user_id'])->via('taskUsers'); | |
} | |
// ########### handle responsible users ########### | |
/** | |
* Returns an ActiveQuery for all responsible task users of this task. | |
* | |
* @return \yii\db\ActiveQuery | |
*/ | |
public function getTaskResponsible() | |
{ | |
return $this->hasMany(TaskUser::class, ['task_id' => 'id'])->andOnCondition(['user_type' => self::USER_RESPONSIBLE]); | |
} | |
public function hasTaskResponsible() | |
{ | |
return !empty($this->taskResponsible); | |
} | |
/** | |
* Returns an ActiveQuery for all responsible user models of this task. | |
* | |
* @return \yii\db\ActiveQuery | |
*/ | |
public function getTaskResponsibleUsers() | |
{ | |
return $this->hasMany(User::class, ['id' => 'user_id'])->via('taskResponsible'); | |
} | |
public function isTaskResponsible($user = null) | |
{ | |
if (!$user && !Yii::$app->user->isGuest) { | |
$user = Yii::$app->user->getIdentity(); | |
} else if (!$user) { | |
return false; | |
} | |
$taskResponsible = array_filter($this->taskResponsible, function (TaskUser $p) use ($user) { | |
return $p->user_id == $user->id; | |
}); | |
return !empty($taskResponsible); | |
} | |
public function isOwner($user = null) | |
{ | |
if (!$user && !Yii::$app->user->isGuest) { | |
$user = Yii::$app->user->getIdentity(); | |
} else if (!$user) { | |
return false; | |
} | |
return $this->content->created_by === $user->getId(); | |
} | |
public function addTaskResponsible($user, $sendNotification = true) | |
{ | |
$user = (is_string($user)) ? User::findOne(['guid' => $user]) : $user; | |
if (!$user) { | |
return false; | |
} | |
if (!$this->isTaskResponsible($user)) { | |
$taskResponsible = new TaskUser([ | |
'task_id' => $this->id, | |
'user_id' => $user->id, | |
'user_type' => self::USER_RESPONSIBLE, | |
'sendNotificationOnCreation' => $sendNotification | |
]); | |
return $taskResponsible->save(); | |
} | |
return false; | |
} | |
public function isOverdue() | |
{ | |
return $this->schedule->isOverdue(); | |
} | |
/** | |
* Returns an ActiveQuery for all assigned task users of this task. | |
* | |
* @return \yii\db\ActiveQuery | |
*/ | |
public function getTaskReminder() | |
{ | |
$query = $this->hasMany(TaskReminder::className(), ['task_id' => 'id']); | |
return $query; | |
} | |
// ########### handle task items ########### | |
/** | |
* Returns an ActiveQuery for all task items of this task. | |
* | |
* @return ActiveQuery | |
*/ | |
public function getItems() | |
{ | |
return $this->hasMany(TaskItem::class, ['task_id' => 'id'])->orderBy(['sort_order' => SORT_ASC]); | |
} | |
public function hasItems() | |
{ | |
// Todo check task_items and subtask-Items | |
return !empty($this->items); | |
} | |
public function saveNewItems() | |
{ | |
if ($this->newItems == null) { | |
return; | |
} | |
foreach ($this->newItems as $itemText) { | |
$this->addItem($itemText); | |
} | |
// Reset cached items | |
unset($this->items); | |
} | |
public function addItem($itemText) | |
{ | |
if (trim($itemText) === '') { | |
return; | |
} | |
$item = new TaskItem(); | |
$item->task_id = $this->id; | |
$item->title = $itemText; | |
$item->save(); | |
return $item; | |
} | |
/** | |
* Sets the newItems array, which is used for creating and updating (afterSave) | |
* the task, by saving all valid item title contained in the given array. | |
* @param array $newItemArr | |
*/ | |
public function setNewItems($newItemArr) | |
{ | |
$this->newItems = TaskItem::filterValidItems($newItemArr); | |
} | |
/** | |
* Sets the editItems array, which is used for updating (afterSave) | |
* the task. The given array has to contain task item ids as key and an title | |
* as values. | |
* @param array $editItemArr | |
*/ | |
public function setEditItems($editItemArr) | |
{ | |
$this->editItems = TaskItem::filterValidItems($editItemArr); | |
} | |
/** | |
* @param array $items | |
* @throws \yii\db\Exception | |
*/ | |
public function confirm($items = []) | |
{ | |
foreach ($items as $itemID) { | |
$item = TaskItem::findOne(['id' => $itemID, 'task_id' => $this->id]); | |
if ($item) { | |
$item->completed = 1; | |
$item->save(); | |
} | |
} | |
} | |
/** | |
* @throws \yii\db\Exception | |
*/ | |
public function completeItems() | |
{ | |
TaskItem::updateAll(['completed' => 1], ['task_id' => $this->id]); | |
} | |
/** | |
* Returns the total number of confirmed users got this message | |
* | |
* @return int | |
*/ | |
public function getConfirmedCount() | |
{ | |
return $this->getItems()->where(['completed' => true])->count(); | |
} | |
public function isPending() | |
{ | |
return $this->state->isPending(); | |
} | |
public function isInProgress() | |
{ | |
return $this->state->isInProgress(); | |
} | |
public function isPendingReview() | |
{ | |
return $this->state->isPendingReview(); | |
} | |
public function isCompleted() | |
{ | |
return $this->state->isCompleted(); | |
} | |
public function canReview($user = null) | |
{ | |
return $this->review && $this->isTaskResponsible($user); | |
} | |
/** | |
* Additional canEdit check for responsible users. | |
* @return bool | |
* @see Content::canEdit() | |
*/ | |
public function canEdit() | |
{ | |
if($this->isNewRecord) { | |
return $this->content->container->can([CreateTask::class, ManageTasks::class]); | |
} else if(!$this->hasTaskResponsible()) { | |
return $this->content->container->can([ManageTasks::class]); | |
} | |
return $this->isTaskResponsible(); | |
} | |
// ########### handle notifications ########### | |
/** | |
* Filters responsible users from the list of assigned users | |
* | |
* @return array|User[] | |
*/ | |
public function filterResponsibleAssigned() | |
{ | |
$responsible = $this->getTaskResponsibleUsers()->select(['id']); | |
$filteredAssigned = $this->getTaskAssignedUsers() | |
->where(['not in', 'id', $responsible]) | |
->all(); | |
return $filteredAssigned; | |
} | |
public function deleteOldNotifications($notificationClassName = null) | |
{ | |
if (!$notificationClassName) { | |
// delete all old notifications - used for reset | |
$notifications = Notification::find()->where(['source_class' => self::class, 'source_pk' => $this->id, 'space_id' => $this->content->container->id])->all(); | |
foreach ($notifications as $notification) { | |
$notification->delete(); | |
} | |
} | |
else { | |
// delete specific old notifications | |
$notifications = Notification::find()->where(['class' => $notificationClassName, 'source_class' => self::class, 'source_pk' => $this->id, 'space_id' => $this->content->container->id])->all(); | |
foreach ($notifications as $notification) { | |
$notification->delete(); | |
} | |
} | |
} | |
/** | |
* Access url of the source content or other view | |
* | |
* @return string the timezone this item was originally saved, note this is | |
*/ | |
public function getTitle() | |
{ | |
return $this->title; | |
} | |
/** | |
* Returns a badge for the snippet | |
* | |
* @return string the timezone this item was originally saved, note this is | |
*/ | |
public function getBadge() | |
{ | |
if ($this->schedule->isOverdue()) | |
return Label::danger(Yii::t('TasksModule.views_index_index', 'Overdue'))->icon('fa fa-exclamation-triangle')->options(['style' => 'margin-right: 3px;'])->right(); | |
return null; | |
} | |
/** | |
* @inheritdoc | |
*/ | |
public function getSearchAttributes() | |
{ | |
$itemTitles = ""; | |
$itemDescriptions = ""; | |
foreach ($this->items as $item) { | |
$itemTitles .= $item->title; | |
$itemDescriptions .= $item->description; | |
} | |
return [ | |
'title' => $this->title, | |
'description' => $this->description, | |
'itemTitles' => $itemTitles, | |
'itemDescriptions' => $itemDescriptions | |
]; | |
} | |
/** | |
* handle task specific permissions | |
* @return bool | |
*/ | |
public function canProcess($user = null) | |
{ | |
if(!$user && Yii::$app->user->isGuest) { | |
return false; | |
} | |
if(!$user) { | |
$user = Yii::$app->user->getIdentity(); | |
} | |
$permissionManager = new ContentContainerPermissionManager([ | |
'contentContainer' => $this->content->container, | |
'subject' => $user | |
]); | |
return (!$this->hasTaskAssigned() && $permissionManager->can(ProcessUnassignedTasks::class)); | |
} | |
/** | |
* handle task specific permissions | |
* @return bool | |
*/ | |
public function canCheckItems() | |
{ | |
return (($this->isTaskResponsible() || $this->isTaskAssigned() || $this->canProcess()) && (!($this->isCompleted()))); | |
} | |
/** | |
* Only responsible users can review task | |
* @return bool | |
*/ | |
public function canReviewTask() | |
{ | |
return (self::isTaskResponsible()); | |
} | |
/** | |
* handle task specific permissions | |
* @return bool | |
*/ | |
public function canResetTask() | |
{ | |
return (self::isTaskResponsible() && (self::isCompleted())); | |
} | |
/** | |
* handle task specific permissions | |
* @return bool | |
*/ | |
public function canResortItems() | |
{ | |
return (self::isTaskResponsible() && (!self::isCompleted())); | |
} | |
// ########### handle view-specific ########### | |
/** | |
* Returns the percentage of task | |
* | |
* @return int | |
*/ | |
public function getPercent() | |
{ | |
// $denominator = TaskItem::find()->where(['task_id' => $this->id])->count(); | |
$denominator = $this->getItems()->count(); | |
// add STATUS_IN_PROGRESS and STATUS_COMPLETED | |
$denominator += 2; | |
// handle special status STATUS_PENDING_REVIEW | |
if ($this->review) { | |
$denominator += 1; | |
} | |
if ($denominator == 0) | |
return 0; | |
$counter = $this->getConfirmedCount(); | |
if (self::isInProgress()) | |
$counter += 1; | |
elseif (self::isCompleted() && !$this->review) | |
$counter += 2; | |
elseif (self::isPendingReview() && $this->review) | |
$counter += 2; | |
elseif (self::isCompleted() && $this->review) | |
$counter += 3; | |
return $counter / $denominator * 100; | |
} | |
/** | |
* Returns additional labels | |
* | |
* @param array $labels | |
* @param bool $includeContentName | |
* @return Label[]|string[] | |
*/ | |
public function getLabels($labels = [], $includeContentName = true) | |
{ | |
switch ($this->status) { | |
case self::STATUS_PENDING : | |
$labels[] = Label::defaultType(Yii::t('TasksModule.views_index_index', 'Pending'))->icon('fa fa-info-circle')->sortOrder(350); | |
break; | |
case self::STATUS_IN_PROGRESS : | |
$labels[] = Label::info(Yii::t('TasksModule.views_index_index', 'In Progress'))->icon('fa fa-edit')->sortOrder(350); | |
break; | |
case self::STATUS_PENDING_REVIEW : | |
$labels[] = Label::warning(Yii::t('TasksModule.views_index_index', 'Pending Review'))->icon('fa fa-exclamation-triangle')->sortOrder(350); | |
break; | |
case self::STATUS_COMPLETED : | |
$labels[] = Label::success(Yii::t('TasksModule.views_index_index', 'Completed'))->icon('fa fa-check-square')->sortOrder(350); | |
break; | |
default: | |
break; | |
} | |
if ($this->schedule->isOverdue()) | |
$labels[] = Label::danger(Yii::t('TasksModule.views_index_index', 'Overdue'))->icon('fa fa-exclamation-triangle')->sortOrder(360); | |
return parent::getLabels($labels, $includeContentName); | |
} | |
public function moveItemIndex($itemId, $newIndex) | |
{ | |
$this->checklist->moveItemIndex($itemId, $newIndex); | |
} | |
/** | |
* @throws \Exception | |
* @throws \yii\db\StaleObjectException | |
*/ | |
public function beforeRemoveUser() | |
{ | |
$notifications = Notification::find()->where(['source_class' => self::className(), 'source_pk' => $this->id, 'space_id' => $this->content->contentContainer->id])->all(); | |
foreach ($notifications as $notification) { | |
$notification->delete(); | |
} | |
} | |
/** | |
* @param $userId | |
* @return boolw | |
* @throws \Exception | |
* @throws \yii\db\StaleObjectException | |
*/ | |
public function removeUser($userId) | |
{ | |
if (empty($userId) || !isset($userId)) { | |
return false; | |
} | |
$taskAssigned = $this->getAssignedTaskUsers()->where(['task_user.user_id' => $userId])->all(); | |
foreach ($taskAssigned as $assigned) { | |
$assigned->delete(); | |
} | |
$taskResponsible = $this->getTaskResponsible()->where(['task_user.user_id' => $userId])->all(); | |
foreach ($taskResponsible as $responsible) { | |
$responsible->delete(); | |
} | |
} | |
public function getColor() | |
{ | |
if($this->task_list_id && $this->list) { | |
return $this->list->getColor(); | |
} | |
} | |
} |