|
<?php |
|
|
|
namespace Kanboard\Model; |
|
|
|
use Kanboard\Core\Base; |
|
use Kanboard\Core\Security\Token; |
|
use Kanboard\Core\Security\Role; |
|
use Kanboard\Model\TaskModel; |
|
use Kanboard\Model\TaskFileModel; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ProjectModel extends Base |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
const TABLE = 'projects'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
const ACTIVE = 1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
const INACTIVE = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
const TYPE_PRIVATE = 1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
const TYPE_TEAM = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getById($project_id) |
|
{ |
|
return $this->db->table(self::TABLE)->eq('id', $project_id)->findOne(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getByIdWithOwner($project_id) |
|
{ |
|
return $this->db->table(self::TABLE) |
|
->columns(self::TABLE.'.*', UserModel::TABLE.'.username AS owner_username', UserModel::TABLE.'.name AS owner_name') |
|
->eq(self::TABLE.'.id', $project_id) |
|
->join(UserModel::TABLE, 'id', 'owner_id') |
|
->findOne(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getByIdWithOwnerAndTaskCount($project_id) |
|
{ |
|
return $this->db->table(self::TABLE) |
|
->columns( |
|
self::TABLE.'.*', |
|
UserModel::TABLE.'.username AS owner_username', |
|
UserModel::TABLE.'.name AS owner_name', |
|
"(SELECT count(*) FROM tasks WHERE tasks.project_id=projects.id AND tasks.is_active='1') AS nb_active_tasks" |
|
) |
|
->eq(self::TABLE.'.id', $project_id) |
|
->join(UserModel::TABLE, 'id', 'owner_id') |
|
->join(TaskModel::TABLE, 'project_id', 'id') |
|
->findOne(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getByName($name) |
|
{ |
|
return $this->db->table(self::TABLE)->eq('name', $name)->findOne(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getByIdentifier($identifier) |
|
{ |
|
if (empty($identifier)) { |
|
return false; |
|
} |
|
|
|
return $this->db->table(self::TABLE)->eq('identifier', strtoupper($identifier))->findOne(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getByEmail($email) |
|
{ |
|
if (empty($email)) { |
|
return false; |
|
} |
|
|
|
return $this->db->table(self::TABLE)->eq('email', $email)->findOne(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getByToken($token) |
|
{ |
|
if (empty($token)) { |
|
return false; |
|
} |
|
|
|
return $this->db->table(self::TABLE)->eq('token', $token)->eq('is_public', 1)->findOne(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getFirst() |
|
{ |
|
return $this->db->table(self::TABLE)->findOne(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function isPrivate($project_id) |
|
{ |
|
return $this->db->table(self::TABLE)->eq('id', $project_id)->eq('is_private', 1)->exists(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getAll() |
|
{ |
|
return $this->db->table(self::TABLE)->asc('name')->findAll(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getAllByIds(array $project_ids) |
|
{ |
|
if (empty($project_ids)) { |
|
return array(); |
|
} |
|
|
|
return $this->db->table(self::TABLE)->in('id', $project_ids)->asc('name')->findAll(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getAllIds() |
|
{ |
|
return $this->db->table(self::TABLE)->asc('name')->findAllByColumn('id'); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getList($prependNone = true, $noPrivateProjects = true) |
|
{ |
|
if ($noPrivateProjects) { |
|
$projects = $this->db->hashtable(self::TABLE)->eq('is_private', 0)->asc('name')->getAll('id', 'name'); |
|
} else { |
|
$projects = $this->db->hashtable(self::TABLE)->asc('name')->getAll('id', 'name'); |
|
} |
|
|
|
if ($prependNone) { |
|
return array(t('None')) + $projects; |
|
} |
|
|
|
return $projects; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getAllByStatus($status) |
|
{ |
|
return $this->db |
|
->table(self::TABLE) |
|
->asc('name') |
|
->eq('is_active', $status) |
|
->findAll(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getListByStatus($status) |
|
{ |
|
return $this->db |
|
->hashtable(self::TABLE) |
|
->asc('name') |
|
->eq('is_active', $status) |
|
->getAll('id', 'name'); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function countByStatus($status) |
|
{ |
|
return $this->db |
|
->table(self::TABLE) |
|
->eq('is_active', $status) |
|
->count(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getColumnStats(array &$project) |
|
{ |
|
$project['columns'] = $this->columnModel->getAllWithTaskCount($project['id']); |
|
$project['nb_active_tasks'] = 0; |
|
|
|
foreach ($project['columns'] as $column) { |
|
$project['nb_active_tasks'] += $column['nb_open_tasks']; |
|
} |
|
|
|
return $project; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function applyColumnStats(array $projects) |
|
{ |
|
foreach ($projects as &$project) { |
|
$this->getColumnStats($project); |
|
} |
|
|
|
return $projects; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getQueryColumnStats(array $project_ids) |
|
{ |
|
if (empty($project_ids)) { |
|
return $this->db->table(ProjectModel::TABLE)->eq(ProjectModel::TABLE.'.id', 0); |
|
} |
|
|
|
return $this->db |
|
->table(ProjectModel::TABLE) |
|
->columns(self::TABLE.'.*', UserModel::TABLE.'.username AS owner_username', UserModel::TABLE.'.name AS owner_name') |
|
->join(UserModel::TABLE, 'id', 'owner_id') |
|
->in(self::TABLE.'.id', $project_ids) |
|
->callback(array($this, 'applyColumnStats')); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getQueryByProjectIds(array $projectIds) |
|
{ |
|
if (empty($projectIds)) { |
|
return $this->db->table(ProjectModel::TABLE)->eq(ProjectModel::TABLE.'.id', 0); |
|
} |
|
|
|
return $this->db |
|
->table(ProjectModel::TABLE) |
|
->columns(self::TABLE.'.*', UserModel::TABLE.'.username AS owner_username', UserModel::TABLE.'.name AS owner_name') |
|
->join(UserModel::TABLE, 'id', 'owner_id') |
|
->in(self::TABLE.'.id', $projectIds); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function create(array $values, $userId = 0, $addUser = false) |
|
{ |
|
if (! empty($userId) && ! $this->userModel->exists($userId)) { |
|
return false; |
|
} |
|
|
|
$this->db->startTransaction(); |
|
|
|
$values['token'] = ''; |
|
$values['last_modified'] = time(); |
|
$values['is_private'] = empty($values['is_private']) ? 0 : 1; |
|
$values['owner_id'] = $userId; |
|
|
|
if (! empty($values['identifier'])) { |
|
$values['identifier'] = strtoupper($values['identifier']); |
|
} |
|
|
|
$this->helper->model->convertIntegerFields($values, array('priority_default', 'priority_start', 'priority_end', 'task_limit')); |
|
|
|
if (! $this->db->table(self::TABLE)->save($values)) { |
|
$this->db->cancelTransaction(); |
|
return false; |
|
} |
|
|
|
$project_id = $this->db->getLastId(); |
|
|
|
if (! $this->boardModel->create($project_id, $this->boardModel->getUserColumns())) { |
|
$this->db->cancelTransaction(); |
|
return false; |
|
} |
|
|
|
if (! $this->swimlaneModel->create($project_id, t('Default swimlane'))) { |
|
$this->db->cancelTransaction(); |
|
return false; |
|
} |
|
|
|
if ($addUser && $userId) { |
|
$this->projectUserRoleModel->addUser($project_id, $userId, Role::PROJECT_MANAGER); |
|
} |
|
|
|
$this->categoryModel->createDefaultCategories($project_id); |
|
|
|
$this->db->closeTransaction(); |
|
|
|
return (int) $project_id; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function isModifiedSince($project_id, $timestamp) |
|
{ |
|
return (bool) $this->db->table(self::TABLE) |
|
->eq('id', $project_id) |
|
->gt('last_modified', $timestamp) |
|
->count(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function updateModificationDate($project_id) |
|
{ |
|
return $this->db->table(self::TABLE)->eq('id', $project_id)->update(array( |
|
'last_modified' => time() |
|
)); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function update(array $values) |
|
{ |
|
if (! empty($values['identifier'])) { |
|
$values['identifier'] = strtoupper($values['identifier']); |
|
} |
|
|
|
if (! empty($values['start_date'])) { |
|
$values['start_date'] = $this->dateParser->getIsoDate($values['start_date']); |
|
} |
|
|
|
if (! empty($values['end_date'])) { |
|
$values['end_date'] = $this->dateParser->getIsoDate($values['end_date']); |
|
} |
|
|
|
if (! empty($values['owner_id']) && ! $this->userModel->exists($values['owner_id'])) { |
|
return false; |
|
} |
|
|
|
$values['per_swimlane_task_limits'] = empty($values['per_swimlane_task_limits']) ? 0 : 1; |
|
|
|
$this->helper->model->convertIntegerFields($values, array('priority_default', 'priority_start', 'priority_end', 'task_limit')); |
|
|
|
$updates = $values; |
|
unset($updates['id']); |
|
return $this->exists($values['id']) && |
|
$this->db->table(self::TABLE)->eq('id', $values['id'])->save($updates); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function remove($project_id) |
|
{ |
|
|
|
$this->projectFileModel->removeAll($project_id); |
|
|
|
|
|
$file_ids = $this->db |
|
->table(TaskFileModel::TABLE) |
|
->eq(TaskModel::TABLE.'.project_id', $project_id) |
|
->join(TaskModel::TABLE, 'id', 'task_id', TaskFileModel::TABLE) |
|
->findAllByColumn(TaskFileModel::TABLE.'.id'); |
|
|
|
foreach ($file_ids as $file_id) { |
|
$this->taskFileModel->remove($file_id); |
|
} |
|
|
|
|
|
$this->db->table(TagModel::TABLE)->eq('project_id', $project_id)->remove(); |
|
return $this->db->table(self::TABLE)->eq('id', $project_id)->remove(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function exists($project_id) |
|
{ |
|
return $this->db->table(self::TABLE)->eq('id', $project_id)->exists(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function enable($project_id) |
|
{ |
|
return $this->exists($project_id) && |
|
$this->db |
|
->table(self::TABLE) |
|
->eq('id', $project_id) |
|
->update(array('is_active' => 1)); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function disable($project_id) |
|
{ |
|
return $this->exists($project_id) && |
|
$this->db |
|
->table(self::TABLE) |
|
->eq('id', $project_id) |
|
->update(array('is_active' => 0)); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function enablePublicAccess($project_id) |
|
{ |
|
return $this->exists($project_id) && |
|
$this->db |
|
->table(self::TABLE) |
|
->eq('id', $project_id) |
|
->save(array('is_public' => 1, 'token' => Token::getToken())); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function disablePublicAccess($project_id) |
|
{ |
|
return $this->exists($project_id) && |
|
$this->db |
|
->table(self::TABLE) |
|
->eq('id', $project_id) |
|
->save(array('is_public' => 0, 'token' => '')); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function changeGlobalTagUsage($project_id, $global_tags) |
|
{ |
|
return $this->exists($project_id) && |
|
$this->db |
|
->table(self::TABLE) |
|
->eq('id', $project_id) |
|
->save(array('enable_global_tags' => $global_tags)); |
|
} |
|
} |
|
|