function show() { global $page, $db, $user, $fs, $proj; $page->setTitle($fs->prefs['page_title'] . L('reports')); $events = array(1 => L('taskopened'), 13 => L('taskreopened'), 2 => L('taskclosed'), 3 => L('taskedited'), 14 => L('assignmentchanged'), 29 => L('events.useraddedtoassignees'), 4 => L('commentadded'), 5 => L('commentedited'), 6 => L('commentdeleted'), 7 => L('attachmentadded'), 8 => L('attachmentdeleted'), 11 => L('relatedadded'), 12 => L('relateddeleted'), 9 => L('notificationadded'), 10 => L('notificationdeleted'), 17 => L('reminderadded'), 18 => L('reminderdeleted')); $user_events = array(30 => L('created'), 31 => L('deleted')); $page->assign('events', $events); $page->assign('user_events', $user_events); $sort = strtoupper(Get::enum('sort', array('desc', 'asc'))); $where = array(); $params = array(); $orderby = ''; switch (Get::val('order')) { case 'type': $orderby = "h.event_type {$sort}, h.event_date {$sort}"; break; case 'user': $orderby = "user_id {$sort}, h.event_date {$sort}"; break; case 'date': default: $orderby = "h.event_date {$sort}, h.event_type {$sort}"; } foreach (Get::val('events', array()) as $eventtype) { $where[] = 'h.event_type = ?'; $params[] = $eventtype; } $where = '(' . implode(' OR ', $where) . ')'; if ($proj->id) { $where = $where . 'AND (t.project_id = ? OR h.event_type > 29) '; $params[] = $proj->id; } if (($fromdate = Req::val('fromdate')) || Req::val('todate')) { $where .= ' AND '; $todate = Req::val('todate'); if ($fromdate) { $where .= ' h.event_date > ?'; $params[] = Flyspray::strtotime($fromdate) + 0; } if ($todate && $fromdate) { $where .= ' AND h.event_date < ?'; $params[] = Flyspray::strtotime($todate) + 86400; } else { if ($todate) { $where .= ' h.event_date < ?'; $params[] = Flyspray::strtotime($todate) + 86400; } } } $histories = array(); if (count(Get::val('events'))) { if (Get::num('event_number') > 0) { $db->setLimit(Get::num('event_number')); } $histories = $db->x->getAll("SELECT h.*, t.*, p.project_prefix\n FROM {history} h\n LEFT JOIN {tasks} t ON h.task_id = t.task_id\n LEFT JOIN {projects} p ON t.project_id = p.project_id\n WHERE {$where}\n ORDER BY {$orderby}", null, $params); } $page->assign('histories', $histories); $page->assign('sort', $sort); $page->pushTpl('reports.tpl'); }
function area_prefs() { global $page, $user, $fs; $page->assign('groups', Flyspray::ListGroups()); $page->assign('all_groups', Flyspray::listallGroups($user->id)); $page->assign('theuser', $user); $page->setTitle($fs->prefs['page_title'] . L('editmydetails')); }
function setTheme($theme = '') { // Check available themes $themes = Flyspray::listThemes(); if (in_array($theme, $themes)) { $this->_theme = $theme . '/'; } else { $this->_theme = $themes[0] . '/'; } }
/** * Manually add effort to the effort table for this issue / user. * * @param $effort_to_add int Amount of Effort in hours to add to effort table. */ public function addEffort($effort_to_add, $proj) { global $db; $effort = self::EditStringToSeconds($effort_to_add, $proj->prefs['hours_per_manday'], $proj->prefs['estimated_effort_format']); if ($effort === FALSE) { Flyspray::show_error(L('invalideffort')); return; } $db->Query('INSERT INTO {effort} (task_id, date_added, user_id,start_timestamp,end_timestamp,effort) VALUES ( ?, ?, ?, ?,?,? )', array($this->_task_id, time(), $this->_userId, time(), time(), $effort)); }
function execute_upgrade_file($folder, $installed_version) { global $db, $page, $conf; // At first the config file $upgrade_path = BASEDIR . '/upgrade/' . $folder; new ConfUpdater(CONFIG_PATH, $upgrade_path); $upgrade_info = parse_ini_file($upgrade_path . '/upgrade.info', true); // dev version upgrade? if ($folder == Flyspray::base_version($installed_version)) { $type = 'develupgrade'; } else { $type = 'defaultupgrade'; } // Next a mix of XML schema files and PHP upgrade scripts if (!isset($upgrade_info[$type])) { die('#1 Bad upgrade.info file.'); } ksort($upgrade_info[$type]); foreach ($upgrade_info[$type] as $file) { if (substr($file, -4) == '.php') { require_once $upgrade_path . '/' . $file; } if (substr($file, -4) == '.xml') { $schema = new adoSchema($db->dblink); $xml = file_get_contents($upgrade_path . '/' . $file); $xml = str_replace('<table name="', '<table name="' . $conf['database']['dbprefix'], $xml); $schema->ParseSchemaString($xml); $schema->ExecuteSchema(null, true); } } // Last but not least global prefs update if (isset($upgrade_info['fsprefs'])) { $sql = $db->Query('SELECT pref_name FROM {prefs}'); $existing = $db->FetchCol($sql); // Add what is missing foreach ($upgrade_info['fsprefs'] as $name => $value) { if (!in_array($name, $existing)) { $db->Query('INSERT INTO {prefs} (pref_name, pref_value) VALUES (?, ?)', array($name, $value)); } } // Delete what is too much foreach ($existing as $name) { if (!isset($upgrade_info['fsprefs'][$name])) { $db->Query('DELETE FROM {prefs} WHERE pref_name = ?', array($name)); } } } $db->Query('UPDATE {prefs} SET pref_value = ? WHERE pref_name = ?', array(basename($upgrade_path), 'fs_ver')); $page->assign('done', true); }
function show($area = null) { global $page, $fs, $db, $proj, $user, $conf; $perpage = '20'; if (isset($user->infos['tasks_perpage'])) { $perpage = $user->infos['tasks_perpage']; } $pagenum = max(1, Get::num('pagenum', 1)); $offset = $perpage * ($pagenum - 1); // Get the visibility state of all columns $visible = explode(' ', trim($proj->id ? $proj->prefs['visible_columns'] : $fs->prefs['visible_columns'])); if (!is_array($visible) || !count($visible) || !$visible[0]) { $visible = array('id'); } list($tasks, $id_list) = Backend::get_task_list($_GET, $visible, $offset, $perpage); $page->assign('tasks', $tasks); $page->assign('offset', $offset); $page->assign('perpage', $perpage); $page->assign('pagenum', $pagenum); $page->assign('visible', $visible); // List of task IDs for next/previous links $_SESSION['tasklist'] = $id_list; $page->assign('total', count($id_list)); // Javascript replacement if (Get::val('toggleadvanced')) { $advanced_search = intval(!Req::val('advancedsearch')); Flyspray::setCookie('advancedsearch', $advanced_search, time() + 60 * 60 * 24 * 30); $_COOKIE['advancedsearch'] = $advanced_search; } // Update check {{{ if (Get::has('hideupdatemsg')) { unset($_SESSION['latest_version']); } else { if ($conf['general']['update_check'] && $user->perms('is_admin') && $fs->prefs['last_update_check'] < time() - 60 * 60 * 24 * 3) { if (!isset($_SESSION['latest_version'])) { $latest = Flyspray::remote_request('http://flyspray.org/version.txt', GET_CONTENTS); //if for some silly reason we get and empty response, we use the actual version $_SESSION['latest_version'] = empty($latest) ? $fs->version : $latest; $db->x->execParam('UPDATE {prefs} SET pref_value = ? WHERE pref_name = ?', array(time(), 'last_update_check')); } } } if (isset($_SESSION['latest_version']) && version_compare($fs->version, $_SESSION['latest_version'], '<')) { $page->assign('updatemsg', true); } // }}} $page->setTitle($fs->prefs['page_title'] . $proj->prefs['project_title'] . ': ' . L('tasklist')); $page->pushTpl('index.tpl'); }
function add_related($arr) { global $log, $col, $db; static $imported = array(); $task = $arr[1] . $arr[2]; list($prefix, $task) = explode(strpos($task, '#') !== false ? '#' : ' ', $task); $task = Flyspray::GetTaskDetails($task, true, $prefix); if (!$task['task_id'] || isset($imported[$task['task_id'] . '-' . $log['version-name']])) { return; } echo sprintf('<p> Adding task %d for revision %d</p>', $task['task_id'], $log['version-name']); flush(); $imported[$task['task_id'] . '-' . $log['version-name']] = true; $db->x->execParam("INSERT INTO {related} (this_task, related_task, {$col}) VALUES (?,?,?)", array($task['task_id'], $log['version-name'], RELATED_SVN)); }
function show() { global $db, $page, $fs; // Some possibly interesting information about the user $sql = $db->x->GetOne('SELECT count(*) FROM {comments} WHERE user_id = ?', null, $this->user->id); $page->assign('comments', $sql); $sql = $db->x->GetOne('SELECT count(*) FROM {tasks} WHERE opened_by = ?', null, $this->user->id); $page->assign('tasks', $sql); $sql = $db->x->GetOne('SELECT count(*) FROM {assigned} WHERE user_id = ?', null, $this->user->id); $page->assign('groups', Flyspray::listallGroups($this->user->id)); $page->assign('assigned', $sql); $page->assign('theuser', $this->user); $page->setTitle($fs->prefs['page_title'] . L('viewprofile')); $page->pushTpl('profile.tpl'); }
function imageAttachment($matches) { global $db, $baseurl, $user; // we'll not blindly make images out of all attachments $ext = substr($matches[1], -3); if (!in_array($ext, array('png', 'jpg', 'gif'))) { return $matches[0]; } $att = $db->x->getRow('SELECT * FROM {attachments} WHERE orig_name = ?', null, $matches[1]); $task = Flyspray::GetTaskDetails($att['task_id']); if ($att && $user->can_view_task($task)) { return sprintf('<img src="%s" alt="%s" />', Filters::noXSS($baseurl . '?getfile=' . $att['attachment_id']), Filters::noXSS($att['orig_name'])); } else { return $matches[0]; } }
/** * Manually add effort to the effort table for this issue / user. * * @param $effort_to_add int amount of effort in hh:mm to add to effort table. */ public function addEffort($effort_to_add, $proj) { global $db; # note: third parameter seem useless, not used by EditStringToSeconds().., maybe drop it.. $effort = self::EditStringToSeconds($effort_to_add, $proj->prefs['hours_per_manday'], $proj->prefs['estimated_effort_format']); if ($effort === FALSE) { Flyspray::show_error(L('invalideffort')); return false; } # quickfix to avoid useless table entries. if ($effort == 0) { Flyspray::show_error(L('zeroeffort')); return false; } else { $db->Query('INSERT INTO {effort} (task_id, date_added, user_id,start_timestamp,end_timestamp,effort) VALUES ( ?, ?, ?, ?,?,? )', array($this->_task_id, time(), $this->_userId, time(), time(), $effort)); return true; } }
function action_edit() { foreach (Get::val('ids') as $task_id) { // Edit or close? If we have a resolution_reason, then close! otherwise, edit. if (Post::val('resolution_reason')) { Backend::close_task($task_id, Post::val('resolution_reason'), Post::val('closure_comment'), Post::val('mark100')); } elseif (count(Post::val('changes'))) { $task = Flyspray::GetTaskDetails($task_id); $args = $task; // import previous values foreach (Post::val('changes') as $change) { $args[$change] = Post::val($change); } if (is_array($args['assigned_to'])) { $args['assigned_to'] = implode(';', $task['assigned_to_uname']); } Backend::edit_task($task, $args); } } return array(SUBMIT_OK, L('masseditsuccessful')); }
/** * action_sendmagic * * @access public * @return array */ function action_sendmagic() { global $db, $baseurl; // Check that the username exists if (strpos(Post::val('user_name'), '@') === false) { $user = Flyspray::getUserDetails(Flyspray::UserNameToId(Post::val('user_name'))); } else { $user_id = $db->x->GetOne('SELECT user_id FROM {users} WHERE email_address = ?', null, Post::val('user_name')); $user = Flyspray::getUserDetails($user_id); } // If the username doesn't exist, throw an error if (!is_array($user) || !count($user)) { return array(ERROR_RECOVER, L('usernotexist')); } $magic_url = md5(uniqid(mt_rand(), true)); // Insert the random "magic url" into the user's profile $db->x->execParam('UPDATE {users} SET magic_url = ? WHERE user_id = ?', array($magic_url, $user['user_id'])); Notifications::send($user['user_id'], ADDRESS_USER, NOTIFY_PW_CHANGE, array($baseurl, $magic_url)); return array(SUBMIT_OK, L('magicurlsent')); }
/** * Returns an array of tasks (respecting pagination) and an ID list (all tasks) * @param array $args * @param array $visible * @param integer $offset * @param integer $comment * @param bool $perpage * @access public * @return array * @version 1.0 */ public static function get_task_list($args, $visible, $offset = 0, $perpage = 20) { global $fs, $proj, $db, $user, $conf; /* build SQL statement {{{ */ // Original SQL courtesy of Lance Conry http://www.rhinosw.com/ $where = $sql_params = array(); // echo '<pre>' . print_r($visible, true) . '</pre>'; // echo '<pre>' . print_r($args, true) . '</pre>'; // PostgreSQL LIKE searches are by default case sensitive, // so we use ILIKE instead. For other databases, in our case // only MySQL/MariaDB, LIKE is good for our purposes. $LIKEOP = 'LIKE'; if ($db->dblink->dataProvider == 'postgres') { $LIKEOP = 'ILIKE'; } $select = ''; $groupby = 't.task_id, '; $cgroupbyarr = array(); // Joins absolutely needed for user viewing rights $from = ' {tasks} t -- All tasks have a project! JOIN {projects} p ON t.project_id = p.project_id'; // Not needed for anonymous users if (!$user->isAnon()) { $from .= ' -- Global group always exists JOIN ({groups} gpg JOIN {users_in_groups} gpuig ON gpg.group_id = gpuig.group_id AND gpuig.user_id = ? ) ON gpg.project_id = 0 -- Project group might exist or not. LEFT JOIN ({groups} pg JOIN {users_in_groups} puig ON pg.group_id = puig.group_id AND puig.user_id = ? ) ON pg.project_id = t.project_id'; $sql_params[] = $user->id; $sql_params[] = $user->id; } // Keep this always, could also used for showing assigned users for a task. // Keeps the overall logic somewhat simpler. $from .= ' LEFT JOIN {assigned} ass ON t.task_id = ass.task_id'; $from .= ' LEFT JOIN {task_tag} tt ON t.task_id = tt.task_id'; $cfrom = $from; // Seems resution name really is needed... $select .= 'lr.resolution_name, '; $from .= ' LEFT JOIN {list_resolution} lr ON t.resolution_reason = lr.resolution_id '; $groupby .= 'lr.resolution_name, '; // Otherwise, only join tables which are really necessary to speed up the db-query if (array_get($args, 'type') || in_array('tasktype', $visible)) { $select .= ' lt.tasktype_name, '; $from .= ' LEFT JOIN {list_tasktype} lt ON t.task_type = lt.tasktype_id '; $groupby .= ' lt.tasktype_id, '; } if (array_get($args, 'status') || in_array('status', $visible)) { $select .= ' lst.status_name, '; $from .= ' LEFT JOIN {list_status} lst ON t.item_status = lst.status_id '; $groupby .= ' lst.status_id, '; } if (array_get($args, 'cat') || in_array('category', $visible)) { $select .= ' lc.category_name AS category_name, '; $from .= ' LEFT JOIN {list_category} lc ON t.product_category = lc.category_id '; $groupby .= 'lc.category_id, '; } if (in_array('votes', $visible)) { $select .= ' (SELECT COUNT(vot.vote_id) FROM {votes} vot WHERE vot.task_id = t.task_id) AS num_votes, '; } $maxdatesql = ' GREATEST((SELECT max(c.date_added) FROM {comments} c WHERE c.task_id = t.task_id), t.date_opened, t.date_closed, t.last_edited_time) '; $search_for_changes = in_array('lastedit', $visible) || array_get($args, 'changedto') || array_get($args, 'changedfrom'); if ($search_for_changes) { $select .= ' GREATEST((SELECT max(c.date_added) FROM {comments} c WHERE c.task_id = t.task_id), t.date_opened, t.date_closed, t.last_edited_time) AS max_date, '; $cgroupbyarr[] = 't.task_id'; } if (array_get($args, 'search_in_comments')) { $from .= ' LEFT JOIN {comments} c ON t.task_id = c.task_id '; $cfrom .= ' LEFT JOIN {comments} c ON t.task_id = c.task_id '; $cgroupbyarr[] = 't.task_id'; } if (in_array('comments', $visible)) { $select .= ' (SELECT COUNT(cc.comment_id) FROM {comments} cc WHERE cc.task_id = t.task_id) AS num_comments, '; } if (in_array('reportedin', $visible)) { $select .= ' lv.version_name AS product_version_name, '; $from .= ' LEFT JOIN {list_version} lv ON t.product_version = lv.version_id '; $groupby .= 'lv.version_id, '; } if (array_get($args, 'opened') || in_array('openedby', $visible)) { $select .= ' uo.real_name AS opened_by_name, '; $from .= ' LEFT JOIN {users} uo ON t.opened_by = uo.user_id '; $groupby .= 'uo.user_id, '; if (array_get($args, 'opened')) { $cfrom .= ' LEFT JOIN {users} uo ON t.opened_by = uo.user_id '; } } if (array_get($args, 'closed')) { $select .= ' uc.real_name AS closed_by_name, '; $from .= ' LEFT JOIN {users} uc ON t.closed_by = uc.user_id '; $groupby .= 'uc.user_id, '; $cfrom .= ' LEFT JOIN {users} uc ON t.closed_by = uc.user_id '; } if (array_get($args, 'due') || in_array('dueversion', $visible)) { $select .= ' lvc.version_name AS closedby_version_name, '; $from .= ' LEFT JOIN {list_version} lvc ON t.closedby_version = lvc.version_id '; $groupby .= 'lvc.version_id, lvc.list_position, '; } if (in_array('os', $visible)) { $select .= ' los.os_name AS os_name, '; $from .= ' LEFT JOIN {list_os} los ON t.operating_system = los.os_id '; $groupby .= 'los.os_id, '; } if (in_array('attachments', $visible)) { $select .= ' (SELECT COUNT(attc.attachment_id) FROM {attachments} attc WHERE attc.task_id = t.task_id) AS num_attachments, '; } if (array_get($args, 'has_attachment')) { $where[] = 'EXISTS (SELECT 1 FROM {attachments} att WHERE t.task_id = att.task_id)'; } # 20150213 currently without recursive subtasks! if (in_array('effort', $visible)) { $select .= ' (SELECT SUM(ef.effort) FROM {effort} ef WHERE t.task_id = ef.task_id) AS effort, '; } if (array_get($args, 'dev') || in_array('assignedto', $visible)) { # not every db system has this feature out of box if ('mysql' == $db->dblink->dataProvider) { #$select .= ' GROUP_CONCAT(u.real_name) AS assigned_to_name, '; # without distinct i see multiple times each assignee # maybe performance penalty due distinct?, solve by better groupby construction? $select .= ' GROUP_CONCAT(DISTINCT u.real_name) AS assigned_to_name, '; # maybe later for building links to users #$select .= ' GROUP_CONCAT(DISTINCT u.real_name ORDER BY u.user_id) AS assigned_to_name, '; #$select .= ' GROUP_CONCAT(DISTINCT u.user_id ORDER BY u.user_id) AS assignedids, '; } else { $select .= ' MIN(u.real_name) AS assigned_to_name, '; $select .= ' (SELECT COUNT(assc.user_id) FROM {assigned} assc WHERE assc.task_id = t.task_id) AS num_assigned, '; } // assigned table is now always included in join $from .= ' LEFT JOIN {users} u ON ass.user_id = u.user_id '; $groupby .= 'ass.task_id, '; if (array_get($args, 'dev')) { $cfrom .= ' LEFT JOIN {users} u ON ass.user_id = u.user_id '; $cgroupbyarr[] = 't.task_id'; $cgroupbyarr[] = 'ass.task_id'; } } # not every db system has this feature out of box if ('mysql' == $db->dblink->dataProvider) { # without distinct i see multiple times each tag (when task has several assignees too) $select .= ' GROUP_CONCAT(DISTINCT tg.tag_name ORDER BY tg.list_position) AS tags, '; $select .= ' GROUP_CONCAT(DISTINCT tg.tag_id ORDER BY tg.list_position) AS tagids, '; $select .= ' GROUP_CONCAT(DISTINCT tg.class ORDER BY tg.list_position) AS tagclass, '; } else { # FIXME: GROUP_CONCAT() for postgresql? $select .= ' MIN(tg.tag_name) AS tags, '; #$select .= ' (SELECT COUNT(tt.tag_id) FROM {task_tag} tt WHERE tt.task_id = t.task_id) AS tagnum, '; $select .= ' MIN(tg.tag_id) AS tagids, '; $select .= " '' AS tagclass, "; } // task_tag join table is now always included in join $from .= ' LEFT JOIN {list_tag} tg ON tt.tag_id = tg.tag_id '; $groupby .= 'tt.task_id, '; $cfrom .= ' LEFT JOIN {list_tag} tg ON tt.tag_id = tg.tag_id '; $cgroupbyarr[] = 't.task_id'; $cgroupbyarr[] = 'tt.task_id'; # use preparsed task description cache for dokuwiki when possible if ($conf['general']['syntax_plugin'] == 'dokuwiki' && FLYSPRAY_USE_CACHE == true) { $select .= ' cache.content desccache, '; $from .= ' LEFT JOIN {cache} cache ON t.task_id=cache.topic AND cache.type="task" '; } else { $select .= 'NULL AS desccache, '; } if (array_get($args, 'only_primary')) { $where[] = 'NOT EXISTS (SELECT 1 FROM {dependencies} dep WHERE dep.dep_task_id = t.task_id)'; } # feature FS#1600 if (array_get($args, 'only_blocker')) { $where[] = 'EXISTS (SELECT 1 FROM {dependencies} dep WHERE dep.dep_task_id = t.task_id)'; } if (array_get($args, 'only_blocked')) { $where[] = 'EXISTS (SELECT 1 FROM {dependencies} dep WHERE dep.task_id = t.task_id)'; } # feature FS#1599 if (array_get($args, 'only_unblocked')) { $where[] = 'NOT EXISTS (SELECT 1 FROM {dependencies} dep WHERE dep.task_id = t.task_id)'; } if (array_get($args, 'hide_subtasks')) { $where[] = 't.supertask_id = 0'; } if (array_get($args, 'only_watched')) { $where[] = 'EXISTS (SELECT 1 FROM {notifications} fsn WHERE t.task_id = fsn.task_id AND fsn.user_id = ?)'; $sql_params[] = $user->id; } if ($proj->id) { $where[] = 't.project_id = ?'; $sql_params[] = $proj->id; } else { if (!$user->isAnon()) { // Anon-case handled later. $allowed = array(); foreach ($fs->projects as $p) { $allowed[] = $p['project_id']; } if (count($allowed) > 0) { $where[] = 't.project_id IN (' . implode(',', $allowed) . ')'; } else { $where[] = '0 = 1'; # always empty result } } } // process users viewing rights, if not anonymous if (!$user->isAnon()) { $where[] = ' ( -- Begin block where users viewing rights are checked. -- Case everyone can see all project tasks anyway and task not private (t.mark_private = 0 AND p.others_view = 1) OR -- Case admin or project manager, can see any task, even private (gpg.is_admin = 1 OR gpg.manage_project = 1 OR pg.is_admin = 1 OR pg.manage_project = 1) OR -- Case allowed to see all tasks, but not private ((gpg.view_tasks = 1 OR pg.view_tasks = 1) AND t.mark_private = 0) OR -- Case allowed to see own tasks (automatically covers private tasks also for this user!) ((gpg.view_own_tasks = 1 OR pg.view_own_tasks = 1) AND (t.opened_by = ? OR ass.user_id = ?)) OR -- Case task is private, but user either opened it or is an assignee (t.mark_private = 1 AND (t.opened_by = ? OR ass.user_id = ?)) OR -- Leave groups tasks as the last one to check. They are the only ones that actually need doing a subquery -- for checking viewing rights. There\'s a chance that a previous check already matched and the subquery is -- not executed at all. All this of course depending on how the database query optimizer actually chooses -- to fetch the results and execute this query... At least it has been given the hint. -- Case allowed to see groups tasks, all projects (NOTE: both global and project specific groups accepted here) -- Strange... do not use OR here with user_id in EXISTS clause, seems to prevent using index with both mysql and -- postgresql, query times go up a lot. So it\'ll be 2 different EXISTS OR\'ed together. (gpg.view_groups_tasks = 1 AND t.mark_private = 0 AND ( EXISTS (SELECT 1 FROM {users_in_groups} WHERE (group_id = pg.group_id OR group_id = gpg.group_id) AND user_id = t.opened_by) OR EXISTS (SELECT 1 FROM {users_in_groups} WHERE (group_id = pg.group_id OR group_id = gpg.group_id) AND user_id = ass.user_id) )) OR -- Case allowed to see groups tasks, current project. Only project group allowed here. (pg.view_groups_tasks = 1 AND t.mark_private = 0 AND ( EXISTS (SELECT 1 FROM {users_in_groups} WHERE group_id = pg.group_id AND user_id = t.opened_by) OR EXISTS (SELECT 1 FROM {users_in_groups} WHERE group_id = pg.group_id AND user_id = ass.user_id) )) ) -- Rights have been checked '; $sql_params[] = $user->id; $sql_params[] = $user->id; $sql_params[] = $user->id; $sql_params[] = $user->id; } /// process search-conditions {{{ $submits = array('type' => 'task_type', 'sev' => 'task_severity', 'due' => 'closedby_version', 'reported' => 'product_version', 'cat' => 'product_category', 'status' => 'item_status', 'percent' => 'percent_complete', 'pri' => 'task_priority', 'dev' => array('ass.user_id', 'u.user_name', 'u.real_name'), 'opened' => array('opened_by', 'uo.user_name', 'uo.real_name'), 'closed' => array('closed_by', 'uc.user_name', 'uc.real_name')); foreach ($submits as $key => $db_key) { $type = array_get($args, $key, $key == 'status' ? 'open' : ''); settype($type, 'array'); if (in_array('', $type)) { continue; } $temp = ''; $condition = ''; foreach ($type as $val) { // add conditions for the status selection if ($key == 'status' && $val == 'closed' && !in_array('open', $type)) { $temp .= ' is_closed = 1 AND'; } elseif ($key == 'status' && !in_array('closed', $type)) { $temp .= ' is_closed = 0 AND'; } if (is_numeric($val) && !is_array($db_key) && !($key == 'status' && $val == 'closed')) { $temp .= ' ' . $db_key . ' = ? OR'; $sql_params[] = $val; } elseif (is_array($db_key)) { if ($key == 'dev' && ($val == 'notassigned' || $val == '0' || $val == '-1')) { $temp .= ' ass.user_id is NULL OR'; } else { foreach ($db_key as $singleDBKey) { if (strpos($singleDBKey, '_name') !== false) { $temp .= ' ' . $singleDBKey . " {$LIKEOP} ? OR"; $sql_params[] = '%' . $val . '%'; } elseif (is_numeric($val)) { $temp .= ' ' . $singleDBKey . ' = ? OR'; $sql_params[] = $val; } } } } // Add the subcategories to the query if ($key == 'cat') { $result = $db->Query('SELECT * FROM {list_category} WHERE category_id = ?', array($val)); $cat_details = $db->FetchRow($result); $result = $db->Query('SELECT * FROM {list_category} WHERE lft > ? AND rgt < ? AND project_id = ?', array($cat_details['lft'], $cat_details['rgt'], $cat_details['project_id'])); while ($row = $db->FetchRow($result)) { $temp .= ' product_category = ? OR'; $sql_params[] = $row['category_id']; } } } if ($temp) { $where[] = '(' . substr($temp, 0, -3) . ')'; } } /// }}} $order_keys = array('id' => 't.task_id', 'project' => 'project_title', 'tasktype' => 'tasktype_name', 'dateopened' => 'date_opened', 'summary' => 'item_summary', 'severity' => 'task_severity', 'category' => 'lc.category_name', 'status' => 'is_closed, item_status', 'dueversion' => 'lvc.list_position', 'duedate' => 'due_date', 'progress' => 'percent_complete', 'lastedit' => 'max_date', 'priority' => 'task_priority', 'openedby' => 'uo.real_name', 'reportedin' => 't.product_version', 'assignedto' => 'u.real_name', 'dateclosed' => 't.date_closed', 'os' => 'los.os_name', 'votes' => 'num_votes', 'attachments' => 'num_attachments', 'comments' => 'num_comments', 'private' => 'mark_private', 'supertask' => 't.supertask_id'); // make sure that only columns can be sorted that are visible (and task severity, since it is always loaded) $order_keys = array_intersect_key($order_keys, array_merge(array_flip($visible), array('severity' => 'task_severity'))); // Implementing setting "Default order by" if (!array_key_exists('order', $args)) { # now also for $proj->id=0 (allprojects) $orderBy = $proj->prefs['sorting'][0]['field']; $sort = $proj->prefs['sorting'][0]['dir']; if (count($proj->prefs['sorting']) > 1) { $orderBy2 = $proj->prefs['sorting'][1]['field']; $sort2 = $proj->prefs['sorting'][1]['dir']; } else { $orderBy2 = 'severity'; $sort2 = 'DESC'; } } else { $orderBy = $args['order']; $sort = $args['sort']; $orderBy2 = 'severity'; $sort2 = 'desc'; } // TODO: Fix this! If something is already ordered by task_id, there's // absolutely no use to even try to order by something else also. $order_column[0] = $order_keys[Filters::enum(array_get($args, 'order', $orderBy), array_keys($order_keys))]; $order_column[1] = $order_keys[Filters::enum(array_get($args, 'order2', $orderBy2), array_keys($order_keys))]; $sortorder = sprintf('%s %s, %s %s, t.task_id ASC', $order_column[0], Filters::enum(array_get($args, 'sort', $sort), array('asc', 'desc')), $order_column[1], Filters::enum(array_get($args, 'sort2', $sort2), array('asc', 'desc'))); $having = array(); $dates = array('duedate' => 'due_date', 'changed' => $maxdatesql, 'opened' => 'date_opened', 'closed' => 'date_closed'); foreach ($dates as $post => $db_key) { $var = $post == 'changed' ? 'having' : 'where'; if ($date = array_get($args, $post . 'from')) { ${$var}[] = '(' . $db_key . ' >= ' . Flyspray::strtotime($date) . ')'; } if ($date = array_get($args, $post . 'to')) { ${$var}[] = '(' . $db_key . ' <= ' . Flyspray::strtotime($date) . ' AND ' . $db_key . ' > 0)'; } } if (array_get($args, 'string')) { $words = explode(' ', strtr(array_get($args, 'string'), '()', ' ')); $comments = ''; $where_temp = array(); if (array_get($args, 'search_in_comments')) { $comments .= " OR c.comment_text {$LIKEOP} ?"; } if (array_get($args, 'search_in_details')) { $comments .= " OR t.detailed_desc {$LIKEOP} ?"; } foreach ($words as $word) { $likeWord = '%' . str_replace('+', ' ', trim($word)) . '%'; $where_temp[] = "(t.item_summary {$LIKEOP} ? OR t.task_id = ? {$comments})"; array_push($sql_params, $likeWord, intval($word)); if (array_get($args, 'search_in_comments')) { array_push($sql_params, $likeWord); } if (array_get($args, 'search_in_details')) { array_push($sql_params, $likeWord); } } $where[] = '(' . implode(array_get($args, 'search_for_all') ? ' AND ' : ' OR ', $where_temp) . ')'; } if ($user->isAnon()) { $where[] = 't.mark_private = 0 AND p.others_view = 1'; if (array_key_exists('status', $args)) { if (in_array('closed', $args['status']) && !in_array('open', $args['status'])) { $where[] = 't.is_closed = 1'; } elseif (in_array('open', $args['status']) && !in_array('closed', $args['status'])) { $where[] = 't.is_closed = 0'; } } } $where = count($where) ? 'WHERE ' . join(' AND ', $where) : ''; // Get the column names of table tasks for the group by statement if (!strcasecmp($conf['database']['dbtype'], 'pgsql')) { $groupby .= "p.project_title, p.project_is_active, "; // Remove this after checking old PostgreSQL docs. // 1 column from task table should be enough, after // already grouping by task_id, there's no possibility // to have anything more in that table to group by. $groupby .= $db->GetColumnNames('{tasks}', 't.task_id', 't.'); } else { $groupby = 't.task_id'; } $having = count($having) ? 'HAVING ' . join(' AND ', $having) : ''; // echo '<pre>' . print_r($args, true) . '</pre>'; // echo '<pre>' . print_r($cgroupbyarr, true) . '</pre>'; $cgroupby = count($cgroupbyarr) ? 'GROUP BY ' . implode(',', array_unique($cgroupbyarr)) : ''; $sqlcount = "SELECT COUNT(*) FROM (SELECT 1, t.task_id, t.date_opened, t.date_closed, t.last_edited_time\n FROM {$cfrom}\n {$where}\n {$cgroupby}\n {$having}) s"; $sqltext = "SELECT t.*, {$select}\np.project_title, p.project_is_active\nFROM {$from}\n{$where}\nGROUP BY {$groupby}\n{$having}\nORDER BY {$sortorder}"; // Very effective alternative with a little bit more work // and if row_number() can be emulated in mysql. Idea: // Move every join and other operation not needed in // the inner clause to select rows to the outer query, // and do the rest when we already know which rows // are in the window to show. Got it to run constantly // under 6000 ms. /* Leave this for next version, don't have enough time for testing. $sqlexperiment = "SELECT * FROM ( SELECT row_number() OVER(ORDER BY task_id) AS rownum, t.*, $select p.project_title, p.project_is_active FROM $from $where GROUP BY $groupby $having ORDER BY $sortorder ) t WHERE rownum BETWEEN $offset AND " . ($offset + $perpage); */ // echo '<pre>'.print_r($sql_params, true).'</pre>'; # for debugging // echo '<pre>'.$sqlcount.'</pre>'; # for debugging // echo '<pre>'.$sqltext.'</pre>'; # for debugging $sql = $db->Query($sqlcount, $sql_params); $totalcount = $db->FetchOne($sql); # 20150313 peterdd: Do not override task_type with tasktype_name until we changed t.task_type to t.task_type_id! We need the id too. $sql = $db->Query($sqltext, $sql_params, $perpage, $offset); // $sql = $db->Query($sqlexperiment, $sql_params); $tasks = $db->fetchAllArray($sql); $id_list = array(); $limit = array_get($args, 'limit', -1); $forbidden_tasks_count = 0; foreach ($tasks as $key => $task) { $id_list[] = $task['task_id']; if (!$user->can_view_task($task)) { unset($tasks[$key]); $forbidden_tasks_count++; } } // Work on this is not finished until $forbidden_tasks_count is always zero. // echo "<pre>$offset : $perpage : $totalcount : $forbidden_tasks_count</pre>"; return array($tasks, $id_list, $totalcount, $forbidden_tasks_count); // # end alternative }
/** * Returns an array of tasks (respecting pagination) and an ID list (all tasks) * @param array $args call by reference because we have to modifiy $_GET if we use default values from a user profile * @param array $visible * @param integer $offset * @param integer $comment * @param bool $perpage * @access public * @return array * @version 1.0 */ function get_task_list(&$args, $visible, $offset = 0, $perpage = null) { global $proj, $db, $user, $conf, $fs; /* build SQL statement {{{ */ // Original SQL courtesy of Lance Conry http://www.rhinosw.com/ $where = $sql_params = array(); $select = ''; $groupby = 't.task_id, '; $from = ' {tasks} t LEFT JOIN {projects} p ON t.project_id = p.project_id LEFT JOIN {list_items} lr ON t.resolution_reason = lr.list_item_id LEFT JOIN {redundant} r ON t.task_id = r.task_id '; // Only join tables which are really necessary to speed up the db-query $from .= ' LEFT JOIN {assigned} ass ON t.task_id = ass.task_id '; $from .= ' LEFT JOIN {users} u ON ass.user_id = u.user_id '; if (array_get($args, 'dev') || in_array('assignedto', $visible)) { $select .= ' MIN(u.real_name) AS assigned_to_name, '; $select .= ' COUNT(ass.user_id) AS num_assigned, '; } if (array_get($args, 'only_primary')) { $from .= ' LEFT JOIN {dependencies} dep ON dep.dep_task_id = t.task_id '; $where[] = 'dep.depend_id IS null'; } if (array_get($args, 'has_attachment')) { $where[] = 'attachment_count > 0'; } // sortable default fields $order_keys = array('id' => 't.task_id %s', 'project' => 'project_title %s', 'dateopened' => 'date_opened %s', 'summary' => 'item_summary %s', 'progress' => 'percent_complete %s', 'lastedit' => 'last_changed_time %s', 'openedby' => 'r.opened_by_real_name %s', 'closedby' => 'r.closed_by_real_name %s', 'changedby' => 'r.last_changed_by_real_name %s', 'assignedto' => 'u.real_name %s', 'dateclosed' => 't.date_closed %s', 'votes' => 'vote_count %s', 'attachments' => 'attachment_count %s', 'comments' => 'comment_count %s', 'state' => 'closed_by %1$s, is_closed %1$s', 'projectlevelid' => 'prefix_id %s', 'private' => 'mark_private %s'); // custom sortable fields foreach ($proj->fields as $field) { if ($field->prefs['list_type'] == LIST_CATEGORY) { // consider hierarchical structure of categories $order_keys['field' . $field->id] = 'lcfield' . $field->id . '.lft %1$s, field' . $field->id . ' %1$s'; } else { $order_keys['field' . $field->id] = 'field' . $field->id . ' %s'; } } // Default user sort column and order if (!$user->isAnon()) { if (!isset($args['sort'])) { $args['sort'] = $user->infos['defaultorder']; } if (!isset($args['order'])) { $usercolumns = explode(' ', $user->infos['defaultsortcolumn']); foreach ($usercolumns as $column) { if (isset($order_keys[$column])) { $args['order'] = $column; break; } } } } // make sure that only columns can be sorted that are visible $order_keys = array_intersect_key($order_keys, array_flip($visible)); $order_column[0] = $order_keys[Filters::enum(array_get($args, 'order', 'id'), array_keys($order_keys))]; $order_column[1] = $order_keys[Filters::enum(array_get($args, 'order2', 'project'), array_keys($order_keys))]; $order_column[0] = sprintf($order_column[0], strtoupper(Filters::enum(array_get($args, 'sort', 'desc'), array('asc', 'desc')))); $order_column[1] = sprintf($order_column[1], strtoupper(Filters::enum(array_get($args, 'sort2', 'desc'), array('asc', 'desc')))); $sortorder = sprintf('%s, %s, t.task_id ASC', $order_column[0], $order_column[1]); // search custom fields $custom_fields_joined = array(); foreach ($proj->fields as $field) { $ref = 'field' . $field->id; if ($field->prefs['field_type'] == FIELD_DATE) { if (!array_get($args, 'field' . $field->id . 'from') && !array_get($args, 'field' . $field->id . 'to')) { continue; } $from .= " LEFT JOIN {field_values} {$ref} ON t.task_id = {$ref}.task_id AND {$ref}.field_id = {$field->id} "; $custom_fields_joined[] = $field->id; if ($date = array_get($args, 'field' . $field->id . 'from')) { $where[] = "({$ref}.field_value >= ?)"; $sql_params[] = Flyspray::strtotime($date); } if ($date = array_get($args, 'field' . $field->id . 'to')) { $where[] = "({$ref}.field_value <= ? AND {$ref}.field_value > 0)"; $sql_params[] = Flyspray::strtotime($date); } } elseif ($field->prefs['field_type'] == FIELD_LIST) { if (in_array('', (array) array_get($args, 'field' . $field->id, array('')))) { continue; } $from .= " LEFT JOIN {field_values} {$ref} ON t.task_id = {$ref}.task_id AND {$ref}.field_id = {$field->id} "; $custom_fields_joined[] = $field->id; $fwhere = array(); foreach ($args['field' . $field->id] as $val) { $fwhere[] = " {$ref}.field_value = ? "; $sql_params[] = $val; } if (count($fwhere)) { $where[] = ' (' . implode(' OR ', $fwhere) . ') '; } } else { if (!($val = array_get($args, 'field' . $field->id))) { continue; } $from .= " LEFT JOIN {field_values} {$ref} ON t.task_id = {$ref}.task_id AND {$ref}.field_id = {$field->id} "; $custom_fields_joined[] = $field->id; $where[] = "({$ref}.field_value LIKE ?)"; // try to determine a valid user ID if necessary if ($field->prefs['field_type'] == FIELD_USER) { $val = Flyspray::UserNameOrId($val); } $sql_params[] = $val; } } // now join custom fields used in columns foreach ($proj->columns as $col => $name) { if (preg_match('/^field(\\d+)$/', $col, $match) && (in_array($col, $visible) || $match[1] == $fs->prefs['color_field'])) { if (!in_array($match[1], $custom_fields_joined)) { $from .= " LEFT JOIN {field_values} {$col} ON t.task_id = {$col}.task_id AND {$col}.field_id = " . intval($match[1]); } $from .= " LEFT JOIN {fields} f{$col} ON f{$col}.field_id = {$col}.field_id "; // join special tables for certain fields if ($proj->fields['field' . $match[1]]->prefs['field_type'] == FIELD_LIST) { $from .= "LEFT JOIN {list_items} li{$col} ON (f{$col}.list_id = li{$col}.list_id AND {$col}.field_value = li{$col}.list_item_id)\n LEFT JOIN {list_category} lc{$col} ON (f{$col}.list_id = lc{$col}.list_id AND {$col}.field_value = lc{$col}.category_id) "; if ($proj->fields['field' . $match[1]]->prefs['list_type'] != LIST_CATEGORY) { $select .= " li{$col}.item_name AS {$col}_name, "; } else { $select .= " lc{$col}.category_name AS {$col}_name, "; } } else { if ($proj->fields['field' . $match[1]]->prefs['field_type'] == FIELD_USER) { $from .= " LEFT JOIN {users} u{$col} ON {$col}.field_value = u{$col}.user_id "; $select .= " u{$col}.user_name AS {$col}_name, "; } } $select .= "{$col}.field_value AS {$col}, "; // adding data to queries not nice, but otherwise sql_params and joins are not in sync } } // open / closed (never thought that I'd use XOR some time) if (in_array('open', array_get($args, 'status', array('open'))) xor in_array('closed', array_get($args, 'status', array()))) { $where[] = ' is_closed = ? '; $sql_params[] = (int) in_array('closed', array_get($args, 'status', array())); } /// process search-conditions {{{ $submits = array('percent' => 'percent_complete', 'dev' => array('a.user_id', 'us.user_name'), 'opened' => array('opened_by', 'r.opened_by_user_name'), 'closed' => array('closed_by', 'r.closed_by_user_name')); // add custom user fields foreach ($submits as $key => $db_key) { $type = array_get($args, $key, ''); settype($type, 'array'); if (in_array('', $type)) { continue; } if ($key == 'dev') { $from .= 'LEFT JOIN {assigned} a ON t.task_id = a.task_id '; $from .= 'LEFT JOIN {users} us ON a.user_id = us.user_id '; } $temp = ''; $condition = ''; foreach ($type as $val) { if (is_numeric($val) && !is_array($db_key)) { $temp .= ' ' . $db_key . ' = ? OR'; $sql_params[] = $val; } elseif (is_array($db_key)) { if ($key == 'dev' && ($val == 'notassigned' || $val == '0' || $val == '-1')) { $temp .= ' a.user_id IS NULL OR'; } else { if (is_numeric($val)) { $condition = ' = ? OR'; } else { $val = '%' . $val . '%'; $condition = ' LIKE ? OR'; } foreach ($db_key as $value) { $temp .= ' ' . $value . $condition; $sql_params[] = $val; } } } } if ($temp) { $where[] = '(' . substr($temp, 0, -3) . ')'; } } /// }}} $having = array(); $dates = array('due_date', 'changed' => 'r.last_changed_time', 'opened' => 'date_opened', 'closed' => 'date_closed'); foreach ($dates as $post => $db_key) { $var = $post == 'changed' ? 'having' : 'where'; if ($date = array_get($args, $post . 'from')) { ${$var}[] = '(' . $db_key . ' >= ' . Flyspray::strtotime($date) . ')'; } if ($date = array_get($args, $post . 'to')) { ${$var}[] = '(' . $db_key . ' <= ' . Flyspray::strtotime($date) . ' AND ' . $db_key . ' > 0)'; } } if (array_get($args, 'string')) { $words = explode(' ', strtr(array_get($args, 'string'), '()', ' ')); $comments = ''; $where_temp = array(); if (array_get($args, 'search_in_comments')) { $from .= 'LEFT JOIN {comments} c ON t.task_id = c.task_id '; $comments .= ' OR c.comment_text LIKE ? '; } if (array_get($args, 'search_in_details')) { $comments .= 'OR t.detailed_desc LIKE ? '; } foreach ($words as $word) { $word = '%' . str_replace('+', ' ', trim($word)) . '%'; $where_temp[] = "(t.item_summary LIKE ? OR t.task_id LIKE ? {$comments})"; array_push($sql_params, $word, $word); if (array_get($args, 'search_in_comments')) { array_push($sql_params, $word); } if (array_get($args, 'search_in_details')) { array_push($sql_params, $word); } } $where[] = '(' . implode(array_get($args, 'search_for_all') ? ' AND ' : ' OR ', $where_temp) . ')'; } if (array_get($args, 'only_watched')) { //join the notification table to get watched tasks $from .= ' LEFT JOIN {notifications} fsn ON t.task_id = fsn.task_id'; $where[] = 'fsn.user_id = ?'; $sql_params[] = $user->id; } if ($proj->id) { $where[] = 't.project_id = ?'; $sql_params[] = $proj->id; } else { $tmpwhere = array(); foreach (array_get($args, 'search_project', array()) as $id) { if ($id) { $tmpwhere[] = 't.project_id = ?'; $sql_params[] = $id; } } if (count($tmpwhere)) { $where[] = '(' . implode(' OR ', $tmpwhere) . ')'; } } $where = count($where) ? 'WHERE ' . join(' AND ', $where) : ''; // Get the column names of table tasks for the group by statement if (!strcasecmp($conf['database']['dbtype'], 'pgsql')) { $order_column[0] = substr($order_column[0], 0, -4); $order_column[1] = substr($order_column[1], 0, -4); $groupby .= "p.project_title, p.project_prefix, {$order_column[0]},{$order_column[1]}, lr.item_name, "; $groupby .= GetColumnNames('{tasks}', 't.task_id', 't'); } else { $groupby = 't.task_id'; } $having = count($having) ? 'HAVING ' . join(' AND ', $having) : ''; $tasks = $db->x->getAll("\n SELECT t.*, r.*, {$select}\n p.project_title, p.project_prefix,\n lr.item_name AS resolution_name\n FROM {$from}\n {$where}\n GROUP BY {$groupby}\n {$having}\n ORDER BY {$sortorder}", null, $sql_params); $id_list = array(); $limit = array_get($args, 'limit', -1); $task_count = 0; foreach ($tasks as $key => $task) { $id_list[] = $task['task_id']; if (!$user->can_view_task($task)) { unset($tasks[$key]); array_pop($id_list); --$task_count; } elseif ($perpage && ($task_count < $offset || $task_count > $offset - 1 + $perpage || $limit > 0 && $task_count >= $limit)) { unset($tasks[$key]); } ++$task_count; } return array($tasks, $id_list); }
public function logout() { // Set cookie expiry time to the past, thus removing them Flyspray::setcookie('flyspray_userid', '', time() - 60); Flyspray::setcookie('flyspray_passhash', '', time() - 60); Flyspray::setcookie('flyspray_project', '', time() - 60); if (Cookie::has(session_name())) { Flyspray::setcookie(session_name(), '', time() - 60); } // Unset all of the session variables. $_SESSION = array(); session_destroy(); return !$this->isAnon(); }
VALUES (?, ?)', array($id, $assignee)); } } } } // set success message $_SESSION['SUCCESS'] = L('tasksupdated'); break; } else { if (!Post::val('resolution_reason')) { Flyspray::show_error(L('noclosereason')); break; } $task_ids = Post::val('ids'); foreach ($task_ids as $task_id) { $task = Flyspray::GetTaskDetails($task_id); if (!$user->can_close_task($task)) { continue; } if ($task['is_closed']) { continue; } Backend::close_task($task_id, Post::val('resolution_reason'), Post::val('closure_comment', ''), Post::val('mark100', false)); } $_SESSION['SUCCESS'] = L('taskclosedmsg'); break; } } else { Flyspray::show_error(L('massopsdisabled')); } }
<?php /* * Multiple Tasks Creation */ if (!defined('IN_FS')) { die('Do not access this file directly.'); } if (!$user->can_open_task($proj) && !$user->perms('add_multiple_tasks')) { Flyspray::show_error(15); } $page->setTitle($fs->prefs['page_title'] . $proj->prefs['project_title'] . ': ' . L('newtask')); $page->assign('old_assigned', ''); $page->pushTpl('newmultitasks.tpl');
FROM {related} r LEFT JOIN {tasks} t ON (r.related_task = t.task_id AND r.this_task = ? OR r.this_task = t.task_id AND r.related_task = ?) LEFT JOIN {list_status} s ON t.item_status = s.status_id LEFT JOIN {list_resolution} res ON t.resolution_reason = res.resolution_id WHERE t.task_id is NOT NULL AND is_duplicate = 0 AND ( t.mark_private = 0 OR ? = 1 ) ORDER BY t.task_id ASC', array($task_id, $task_id, $user->perms('manage_project'))); $related_cleaned = Flyspray::weedOutTasks($user, $db->fetchAllArray($sql)); $page->assign('related', $related_cleaned); $sql = $db->Query('SELECT t.*, r.*, s.status_name, res.resolution_name FROM {related} r LEFT JOIN {tasks} t ON r.this_task = t.task_id LEFT JOIN {list_status} s ON t.item_status = s.status_id LEFT JOIN {list_resolution} res ON t.resolution_reason = res.resolution_id WHERE is_duplicate = 1 AND r.related_task = ? ORDER BY t.task_id ASC', array($task_id)); $duplicates_cleaned = Flyspray::weedOutTasks($user, $db->fetchAllArray($sql)); $page->assign('duplicates', $duplicates_cleaned); $sql = $db->Query('SELECT * FROM {notifications} n LEFT JOIN {users} u ON n.user_id = u.user_id WHERE n.task_id = ?', array($task_id)); $page->assign('notifications', $db->fetchAllArray($sql)); $sql = $db->Query('SELECT * FROM {reminders} r LEFT JOIN {users} u ON r.to_user_id = u.user_id WHERE task_id = ? ORDER BY reminder_id', array($task_id)); $page->assign('reminders', $db->fetchAllArray($sql)); $page->pushTpl('details.tabs.tpl'); if ($user->perms('view_comments') || $proj->prefs['others_view'] || $user->isAnon() && $task_details['task_token'] && Get::val('task_token') == $task_details['task_token']) { $page->pushTpl('details.tabs.comment.tpl');
/** * Processes single command and performs some backend action * * @param FlySprayCommand $cmd * @param Backend $backend * @return mixed */ private function process_command(FlySprayCommand $cmd, Backend &$backend) { $not_cackend_commands = array('active_user', 'get_task_details'); if (!in_array($cmd->action, $not_cackend_commands) && !method_exists($backend, $cmd->action)) { throw new Exception('Needed action is not performed in Backend', API_ECODE_BACKEND_NOT_PORFORM); } global $db; switch ($cmd->action) { case 'active_user': // CommandActiveUser global $user; if ($user->infos['user_name'] != $cmd->id) { $user_id = $db->x->GetOne('SELECT user_id FROM {users} WHERE user_name = ?', null, $cmd->id); if (intval($user_id) > 0) { $user = new User($user_id); } else { throw new Exception('ActiveUser can not be set', API_ECODE_SET_ACTIVE_USER); } } break; case 'add_comment': // CommandAddComment if (!($task = Flyspray::GetTaskDetails($cmd->id))) { throw new Exception('Cannot select task', API_ECODE_SELECT_TASK); } if (!($cid = $backend->add_comment($task, $cmd->ids[0]))) { throw new Exception('Failed adding comment', API_ECODE_ADD_COMMENT); } return $cid; case 'close_task': // CommandCloseTask try { $list_item_id = $this->get_list_item_id('resolution', 'fixed'); } catch (Exception $exc) { throw new Exception($exc->getMessage(), API_ECODE_CLOSE_TASK); } if (!$backend->close_task($cmd->id, $list_item_id, $cmd->ids['comment'], $cmd->ids['mark100'])) { throw new Exception('Cannot close task', API_ECODE_CLOSE_TASK); } break; case 'edit_task': // CommandEditTask // default task fields, another fields should be treated as custom fields $def_fields = array('item_summary', 'project_id', 'percent_complete', 'assignedto'); if (!($task = Flyspray::GetTaskDetails($cmd->id))) { throw new Exception('Cannot select task', API_ECODE_SELECT_TASK); } $args = $task; $this->normalize_task_to_args($args); foreach ($cmd->ids as $param_key => $param_value) { if (in_array($param_key, $def_fields)) { $args[$param_key] = $param_value; } else { if (!($field = $db->x->getRow('SELECT * FROM {fields} WHERE field_name = ?', null, $param_key))) { throw new Exception('Cannot find custom field row for ' . $param_key, API_ECODE_FIELD_NOT_FOUND); } if (!($field_val = $db->x->getRow("SELECT * FROM {list_items} WHERE list_id = ? AND item_name LIKE '%{$param_value}%'", null, $field['list_id']))) { throw new Exception(sprintf('Cannot find field item row for %s like %s', $param_key, $param_value), API_ECODE_FIELD_VALUE_NOT_FOUND); } $args['field' . $field['field_id']] = $field_val['list_item_id']; } } list($status_code, $msg) = $backend->edit_task($task, $args); if ($status_code != SUBMIT_OK) { throw new Exception(sprintf('Failed editing task, status code is "%d", message is "%s"', $status_code, strval($msg)), API_ECODE_EDIT_TASK); } break; case 'assign_to_me': // CommandAssignToMe $user_to_assign = $db->x->getRow('SELECT * FROM {users} WHERE user_name = ?', null, $cmd->id); if (!$user_to_assign) { throw new Exception(sprintf('Username "%s" is not found', $cmd->id), API_ECODE_USERNAME_NOT_FOUND); } $backend->assign_to_me($user_to_assign['user_id'], $cmd->ids); break; case 'get_task_details': if (!($task = Flyspray::GetTaskDetails($cmd->id))) { throw new Exception('Cannot select task', API_ECODE_SELECT_TASK); } return $task; default: throw new Exception('Unrecognized command ' . $cmd->action, API_ECODE_UNRECOGNIZED_COMMAND); } }
/** * Shows an error message * @param string $error_message if it is an integer, an error message from the language file will be loaded * @param bool $die enable/disable redirection (if outside the database modification script) * @param string $advanced_info append a string to the error message * @param string $url alternate redirection * @access public static * @return void * @version 1.0 * @notes if a success and error happens on the same page, a mixed error message will be shown * @todo is the if ($die) meant to be inside the else clause? */ public static function show_error($error_message, $die = true, $advanced_info = null, $url = null) { global $modes, $baseurl; if (!is_int($error_message)) { // in modify.inc.php $_SESSION['ERROR'] = $error_message; } else { $_SESSION['ERROR'] = L('error#') . $error_message . ': ' . L('error' . $error_message); if (!is_null($advanced_info)) { $_SESSION['ERROR'] .= ' ' . $advanced_info; } if ($die) { Flyspray::Redirect(is_null($url) ? $baseurl : $url); } } }
define('BASEDIR', dirname(__FILE__)); define('APPLICATION_PATH', dirname(BASEDIR)); define('OBJECTS_PATH', APPLICATION_PATH . '/includes'); define('TEMPLATE_FOLDER', BASEDIR . '/templates/'); $conf['general']['syntax_plugin'] = ''; require_once OBJECTS_PATH . '/fix.inc.php'; require_once OBJECTS_PATH . '/class.gpc.php'; require_once OBJECTS_PATH . '/class.flyspray.php'; require_once OBJECTS_PATH . '/class.tpl.php'; require_once OBJECTS_PATH . '/constants.inc.php'; require_once OBJECTS_PATH . '/class.database.php'; @(require_once OBJECTS_PATH . '/class.tpl.php'); // --------------------------------------------------------------------- // Application Web locations // --------------------------------------------------------------------- define('APPLICATION_SETUP_INDEX', Flyspray::absoluteURI()); class Setup extends Flyspray { var $mPhpRequired; var $mSupportedDatabases; var $mAvailableDatabases; var $mProceed; var $mPhpVersionStatus; var $mDatabaseStatus; var $xmlStatus; var $mConfigText; var $mHtaccessText; var $mWriteStatus; var $mDbConnection; var $mProductName; /**
define('RELATED_SVN', 2); // Do modes define('MENU_GLOBAL', 1); define('MENU_PROJECT', 2); define('ERROR_INTERNAL', 7); define('ERROR_INPUT', 6); define('ERROR_PERMS', 4); define('ERROR_RECOVER', 3); define('SUBMIT_OK', 2); define('NO_SUBMIT', 1); // Function parameters define('REINDEX', true); define('GET_CONTENTS', true); define('LOCK_FIELD', true); define('USE_DEFAULT', true); define('PLAINTEXT', true); // Others define('MIN_PW_LENGTH', 5); define('LOGIN_ATTEMPTS', 5); define('FS_CACHE_DIR', Flyspray::get_tmp_dir() . DIRECTORY_SEPARATOR . md5($_SERVER['SERVER_NAME'] . BASEDIR)); define('FLYSPRAY_WEBDOT', 'http://webdot.flyspray.org/'); is_dir(FS_CACHE_DIR) || mkdir(FS_CACHE_DIR, 0700); // local installation constants, this file must not exist in the svn repository. if (is_readable(BASEDIR . '/includes/constants.' . $_SERVER['SERVER_NAME'] . '.php')) { include BASEDIR . '/includes/constants.' . $_SERVER['SERVER_NAME'] . '.php'; } defined('FS_ATTACHMENTS_DIR') || define('FS_ATTACHMENTS_DIR', BASEDIR . DIRECTORY_SEPARATOR . 'attachments'); // developers or advanced users only //define('DEBUG_SQL', true); //define('FS_MAIL_DEBUG', true); //define('FS_NO_EMAIL', true);
define('NOTIFY_REL_ADDED', 9); define('NOTIFY_OWNERSHIP', 10); define('NOTIFY_CONFIRMATION', 11); define('NOTIFY_PM_REQUEST', 12); define('NOTIFY_PM_DENY_REQUEST', 13); define('NOTIFY_NEW_ASSIGNEE', 14); define('NOTIFY_REV_DEP', 15); define('NOTIFY_REV_DEP_REMOVED', 16); define('NOTIFY_ADDED_ASSIGNEES', 17); define('NOTIFY_ANON_TASK', 18); define('NOTIFY_PW_CHANGE', 19); define('NOTIFY_NEW_USER', 20); define('NOTIFY_EMAIL', 1); define('NOTIFY_JABBER', 2); define('NOTIFY_BOTH', 3); define('STATUS_UNCONFIRMED', 1); define('STATUS_NEW', 2); define('STATUS_ASSIGNED', 3); define('GET_CONTENTS', true); // Others define('MIN_PW_LENGTH', 5); define('LOGIN_ATTEMPTS', 5); define('FLYSPRAY_WEBDOT', 'http://webdot.flyspray.org/'); define('FS_DOMAIN_HASH', md5($_SERVER['SERVER_NAME'] . BASEDIR)); define('FS_CACHE_DIR', Flyspray::get_tmp_dir() . DIRECTORY_SEPARATOR . FS_DOMAIN_HASH); is_dir(FS_CACHE_DIR) || @mkdir(FS_CACHE_DIR, 0700); // developers or advanced users only define('DEBUG_SQL', true); //define('JABBER_DEBUG', true); //define('JABBER_DEBUG_FILE''/path/to/my/debug/file'); //define('FS_MAIL_LOGFILE', BASEDIR . '/logs/maillog.txt');
ob_clean(); flush(); // finally send out our data printf("%s", $result); } // } }} // Javascript replacement if (Get::val('toggleadvanced')) { $advanced_search = intval(!Req::val('advancedsearch')); Flyspray::setCookie('advancedsearch', $advanced_search, time() + 60 * 60 * 24 * 30); $_COOKIE['advancedsearch'] = $advanced_search; } // Update check {{{ if (Get::has('hideupdatemsg')) { unset($_SESSION['latest_version']); } else { if ($conf['general']['update_check'] && $user->perms('is_admin') && $fs->prefs['last_update_check'] < time() - 60 * 60 * 24 * 3) { if (!isset($_SESSION['latest_version'])) { $latest = Flyspray::remote_request('http://flyspray.org/version.txt', GET_CONTENTS); //if for some silly reason we get and empty response, we use the actual version $_SESSION['latest_version'] = empty($latest) ? $fs->version : $latest; $db->Query('UPDATE {prefs} SET pref_value = ? WHERE pref_name = ?', array(time(), 'last_update_check')); } } } if (isset($_SESSION['latest_version']) && version_compare($fs->version, $_SESSION['latest_version'], '<')) { $page->assign('updatemsg', true); } // }}} $page->setTitle($fs->prefs['page_title'] . $proj->prefs['project_title'] . ': ' . L('tasklist')); $page->pushTpl('index.tpl');
$args['item_summary'] = "Task {$i} ({$subject})"; // 'detailed_desc' // echo $args['item_summary'] . "\r\n"; $ok = Backend::create_task($args); if ($ok === 0) { echo "Failed to create task.\r\n"; } else { list($id, $token) = $ok; $db->Query('UPDATE {tasks} SET opened_by = ?, date_opened = ? WHERE task_id = ?', array($reporter, $opened, $id)); } } // One task in ten of is unconfirmed, probably just bullshit, not assigned to anyone, // and we add just a comment "Cannot reproduce". for ($i = 1; $i <= $maxcomments; $i++) { $taskid = rand(2, $maxtasks + 1); $task = Flyspray::GetTaskDetails($taskid, true); $project = $task['project_id']; $added = time() - rand(1, 315360000); // Find someone who is allowed to add comment, do not use global groups $sqltext = "SELECT uig.user_id\n FROM {users_in_groups} uig\n JOIN {groups} g ON g.group_id = uig.group_id AND g.add_comments = 1\n AND (g.project_id = 0 OR g.project_id = ?)\n WHERE g.group_id NOT IN (1, 2, 7, 8, 9)\n ORDER BY {$RANDOP} "; $sql = $db->Query($sqltext, array($project)); $row = $db->FetchRow($sql); $reporter = new User($row['user_id']); // User might still not be able to add a comment, if he can not see the task... // Just try again until a suitable one comes out from the query. It will finally. // Try to enhance the query also to return fewer unsuitable ones. while (!$reporter->can_view_task($task)) { $row = $db->FetchRow($sql); $reporter = new User($row['user_id']); } $comment = 'Comment.';
/** * Generates a message depending on the $type and using $data * @param integer $type * @param array $data usually contains task_id => $id ... using by-ref to add headers * @return array array($subject, $body) * @access public */ function generate_message($type, &$data) { global $db, $fs, $user; // Get the string of modification $notify_type_msg = array(0 => L('none'), NOTIFY_TASK_OPENED => L('taskopened'), NOTIFY_TASK_CHANGED => L('pm.taskchanged'), NOTIFY_TASK_CLOSED => L('taskclosed'), NOTIFY_TASK_REOPENED => L('pm.taskreopened'), NOTIFY_DEP_ADDED => L('pm.depadded'), NOTIFY_DEP_REMOVED => L('pm.depremoved'), NOTIFY_COMMENT_ADDED => L('commentadded'), NOTIFY_REL_ADDED => L('relatedadded'), NOTIFY_OWNERSHIP => L('ownershiptaken'), NOTIFY_PM_REQUEST => L('pmrequest'), NOTIFY_PM_DENY_REQUEST => L('pmrequestdenied'), NOTIFY_NEW_ASSIGNEE => L('newassignee'), NOTIFY_REV_DEP => L('revdepadded'), NOTIFY_REV_DEP_REMOVED => L('revdepaddedremoved'), NOTIFY_ADDED_ASSIGNEES => L('assigneeadded')); // Generate the nofication message if (isset($data['project']->prefs['notify_subject']) && !$data['project']->prefs['notify_subject']) { $data['project']->prefs['notify_subject'] = '[%p][#%t] %s'; } if (!isset($data['project']->prefs['notify_subject']) || !isset($notify_type_msg[$type])) { $subject = L('notifyfromfs'); } else { $replacement = array('%p' => $data['project']->prefs['project_title'], '%s' => $data['task']['item_summary'], '%t' => $data['task_id'], '%a' => $notify_type_msg[$type], '%u' => $user->infos['user_name'], '%n' => $type); $subject = strtr($data['project']->prefs['notify_subject'], $replacement); $data['headers'] = strtr($data['project']->prefs['mail_headers'], $replacement); } $subject = strtr($subject, "\n", ' '); /* ------------------------------- | List of notification types: | | 1. Task opened | | 2. Task details changed | | 3. Task closed | | 4. Task re-opened | | 5. Dependency added | | 6. Dependency removed | | 7. Comment added | | 9. Related task added | |10. Taken ownership | |11. Confirmation code | |12. PM request | |13. PM denied request | |14. New assignee | |15. Reversed dep | |16. Reversed dep removed | |17. Added to assignees list | |18. Anon-task opened | |19. Password change | |20. New user | ------------------------------- */ $body = L('donotreply') . "\n\n"; switch ($type) { case NOTIFY_TASK_OPENED: $body .= L('newtaskopened') . "\n\n"; $body .= L('userwho') . ' - ' . $user->infos['real_name'] . ' (' . $user->infos['user_name'] . ")\n\n"; $body .= L('attachedtoproject') . ' - ' . $data['project']->prefs['project_title'] . "\n"; $body .= L('summary') . ' - ' . $data['task']['item_summary'] . "\n"; $body .= L('assignedto') . ' - ' . implode(', ', $data['task']['assigned_to_name']) . "\n"; foreach ($data['project']->fields as $field) { $body .= $field->prefs['field_name'] . ' - ' . $field->view($data['task'], array(), PLAINTEXT) . "\n"; } $body .= L('details') . " - \n" . $data['task']['detailed_desc'] . "\n\n"; if (isset($data['files'])) { $body .= L('fileaddedtoo') . "\n\n"; $subject .= ' (' . L('attachmentadded') . ')'; } $body .= L('moreinfo') . "\n"; $body .= CreateURL(array('details', 'task' . $data['task_id'])) . "\n\n"; break; case NOTIFY_TASK_CHANGED: $body .= L('taskchanged') . "\n\n"; $body .= $data['task']['project_prefix'] . '#' . $data['task']['prefix_id'] . ' - ' . $data['task']['item_summary'] . "\n"; $body .= L('userwho') . ': ' . $user->infos['real_name'] . ' (' . $user->infos['user_name'] . ")\n"; foreach ($data['changes'] as $change) { if ($change[0] == 'assigned_to_name') { $change[1] = implode(', ', $change[1]); $change[2] = implode(', ', $change[2]); } if ($change[0] == 'detailed_desc') { $body .= $change[3] . ":\n-------\n" . $change[2] . "\n-------\n"; } else { $body .= $change[3] . ': ' . ($change[1] ? $change[1] : '[-]') . ' -> ' . ($change[2] ? $change[2] : '[-]') . "\n"; } } $body .= "\n" . L('moreinfo') . "\n"; $body .= CreateURL(array('details', 'task' . $data['task_id'])) . "\n\n"; break; case NOTIFY_TASK_CLOSED: $body .= L('notify.taskclosed') . "\n\n"; $body .= $data['task']['project_prefix'] . '#' . $data['task']['prefix_id'] . ' - ' . $data['task']['item_summary'] . "\n"; $body .= L('userwho') . ' - ' . $user->infos['real_name'] . ' (' . $user->infos['user_name'] . ")\n\n"; $body .= L('reasonforclosing') . ' ' . $data['task']['resolution_name'] . "\n"; if (!empty($data['task']['closure_comment'])) { $body .= L('closurecomment') . ' ' . $data['task']['closure_comment'] . "\n\n"; } $body .= L('moreinfo') . "\n"; $body .= CreateURL(array('details', 'task' . $data['task_id'])) . "\n\n"; break; case NOTIFY_TASK_REOPENED: $body .= L('notify.taskreopened') . "\n\n"; $body .= $data['task']['project_prefix'] . '#' . $data['task']['prefix_id'] . ' - ' . $data['task']['item_summary'] . "\n"; $body .= L('userwho') . ' - ' . $user->infos['real_name'] . ' (' . $user->infos['user_name'] . ")\n\n"; $body .= L('moreinfo') . "\n"; $body .= CreateURL(array('details', 'task' . $data['task_id'])) . "\n\n"; break; case NOTIFY_DEP_ADDED: $depend_task = Flyspray::getTaskDetails($data['dep_task']); $body .= L('newdep') . "\n\n"; $body .= $data['task']['project_prefix'] . '#' . $data['task']['prefix_id'] . ' - ' . $data['task']['item_summary'] . "\n"; $body .= L('userwho') . ' - ' . $user->infos['real_name'] . ' (' . $user->infos['user_name'] . ")\n"; $body .= CreateURL(array('details', 'task' . $data['task_id'])) . "\n\n\n"; $body .= L('newdepis') . ':' . "\n\n"; $body .= $data['task']['project_prefix'] . '#' . $depend_task['prefix_id'] . ' - ' . $depend_task['item_summary'] . "\n"; $body .= CreateURL(array('details', 'task' . $depend_task['task_id'])) . "\n\n"; break; case NOTIFY_DEP_REMOVED: $depend_task = Flyspray::getTaskDetails($data['dep_task']); $body .= L('notify.depremoved') . "\n\n"; $body .= $data['task']['project_prefix'] . '#' . $data['task']['prefix_id'] . ' - ' . $data['task']['item_summary'] . "\n"; $body .= L('userwho') . ' - ' . $user->infos['real_name'] . ' (' . $user->infos['user_name'] . ")\n"; $body .= CreateURL(array('details', 'task' . $data['task_id'])) . "\n\n\n"; $body .= L('removeddepis') . ':' . "\n\n"; $body .= $data['task']['project_prefix'] . '#' . $depend_task['prefix_id'] . ' - ' . $depend_task['item_summary'] . "\n"; $body .= CreateURL(array('details', 'task' . $depend_task['task_id'])) . "\n\n"; break; case NOTIFY_COMMENT_ADDED: // Get the comment information $comment = $db->x->getRow('SELECT comment_text FROM {comments} WHERE comment_id = ?', null, $data['cid']); $body .= L('notify.commentadded') . "\n\n"; $body .= $data['task']['project_prefix'] . '#' . $data['task']['prefix_id'] . ' - ' . $data['task']['item_summary'] . "\n"; $body .= L('userwho') . ' - ' . $user->infos['real_name'] . ' (' . $user->infos['user_name'] . ")\n\n"; $body .= "----------\n"; $body .= $comment['comment_text'] . "\n"; $body .= "----------\n\n"; if (isset($data['files'])) { $body .= L('fileaddedtoo') . "\n\n"; $subject .= ' (' . L('attachmentadded') . ')'; } $body .= L('moreinfo') . "\n"; $body .= CreateURL(array('details', 'task' . $data['task_id'])) . '#comment' . $data['cid'] . "\n\n"; break; case NOTIFY_REL_ADDED: $related_task = Flyspray::getTaskDetails($data['rel_task']); $body .= L('notify.relatedadded') . "\n\n"; $body .= $data['task']['project_prefix'] . '#' . $data['task']['prefix_id'] . ' - ' . $data['task']['item_summary'] . "\n"; $body .= L('userwho') . ' - ' . $user->infos['real_name'] . ' (' . $user->infos['user_name'] . ")\n"; $body .= CreateURL(array('details', 'task' . $data['task_id'])) . "\n\n\n"; $body .= L('relatedis') . ':' . "\n\n"; $body .= $data['task']['project_prefix'] . '#' . $related_task['prefix_id'] . ' - ' . $related_task['item_summary'] . "\n"; $body .= CreateURL(array('details', 'task' . $related_task['task_id'])) . "\n\n"; break; case NOTIFY_OWNERSHIP: $body .= implode(', ', $data['task']['assigned_to_name']) . ' ' . L('takenownership') . "\n\n"; $body .= $data['task']['project_prefix'] . '#' . $data['task']['prefix_id'] . ' - ' . $data['task']['item_summary'] . "\n\n"; $body .= L('moreinfo') . "\n"; $body .= CreateURL(array('details', 'task' . $data['task_id'])) . "\n\n"; break; case NOTIFY_CONFIRMATION: $body .= L('noticefrom') . " {$data['project']->prefs['project_title']}\n\n"; $body .= L('addressused') . "\n\n"; $body .= "{$data[0]}index.php?do=register&magic_url={$data[1]}\n\n"; // In case that spaces in the username have been removed $body .= L('username') . ": {$data['2']} \n\n"; break; case NOTIFY_PM_REQUEST: $body .= L('requiresaction') . "\n\n"; $body .= $data['task']['project_prefix'] . '#' . $data['task']['prefix_id'] . ' - ' . $data['task']['item_summary'] . "\n"; $body .= L('userwho') . ' - ' . $user->infos['real_name'] . ' (' . $user->infos['user_name'] . ")\n\n"; $body .= L('moreinfo') . "\n"; $body .= CreateURL(array('details', 'task' . $data['task_id'])) . "\n\n"; break; case NOTIFY_PM_DENY_REQUEST: $body .= L('pmdeny') . "\n\n"; $body .= $data['task']['project_prefix'] . '#' . $data['task']['prefix_id'] . ' - ' . $data['task']['item_summary'] . "\n"; $body .= L('userwho') . ' - ' . $user->infos['real_name'] . ' (' . $user->infos['user_name'] . ")\n\n"; $body .= L('denialreason') . ':' . "\n"; $body .= $data['deny_reason'] . "\n\n"; $body .= L('moreinfo') . "\n"; $body .= CreateURL(array('details', 'task' . $data['task_id'])) . "\n\n"; break; case NOTIFY_NEW_ASSIGNEE: $body .= L('assignedtoyou') . "\n\n"; $body .= $data['task']['project_prefix'] . '#' . $data['task']['prefix_id'] . ' - ' . $data['task']['item_summary'] . "\n"; $body .= L('userwho') . ' - ' . $user->infos['real_name'] . ' (' . $user->infos['user_name'] . ")\n\n"; $body .= L('moreinfo') . "\n"; $body .= CreateURL(array('details', 'task' . $data['task_id'])) . "\n\n"; break; case NOTIFY_REV_DEP: $depend_task = Flyspray::getTaskDetails($data['dep_task']); $body .= L('taskwatching') . "\n\n"; $body .= $data['task']['project_prefix'] . '#' . $data['task']['prefix_id'] . ' - ' . $data['task']['item_summary'] . "\n"; $body .= L('userwho') . ' - ' . $user->infos['real_name'] . ' (' . $user->infos['user_name'] . ")\n"; $body .= CreateURL(array('details', 'task' . $data['task_id'])) . "\n\n\n"; $body .= L('isdepfor') . ':' . "\n\n"; $body .= $data['task']['project_prefix'] . '#' . $depend_task['prefix_id'] . ' - ' . $depend_task['item_summary'] . "\n"; $body .= CreateURL(array('details', 'task' . $depend_task['task_id'])) . "\n\n"; break; case NOTIFY_REV_DEP_REMOVED: $depend_task = Flyspray::getTaskDetails($data['dep_task']); $body .= L('taskwatching') . "\n\n"; $body .= $data['task']['project_prefix'] . '#' . $data['task']['prefix_id'] . ' - ' . $data['task']['item_summary'] . "\n"; $body .= L('userwho') . ' - ' . $user->infos['real_name'] . ' (' . $user->infos['user_name'] . ")\n"; $body .= CreateURL(array('details', 'task' . $data['task_id'])) . "\n\n\n"; $body .= L('isnodepfor') . ':' . "\n\n"; $body .= $data['task']['project_prefix'] . '#' . $depend_task['prefix_id'] . ' - ' . $depend_task['item_summary'] . "\n"; $body .= CreateURL(array('details', 'task' . $depend_task['task_id'])) . "\n\n"; break; case NOTIFY_ADDED_ASSIGNEES: $body .= L('useraddedtoassignees') . "\n\n"; $body .= $data['task']['project_prefix'] . '#' . $data['task']['prefix_id'] . ' - ' . $data['task']['item_summary'] . "\n"; $body .= L('userwho') . ' - ' . $user->infos['real_name'] . ' (' . $user->infos['user_name'] . ")\n"; $body .= CreateURL(array('details', 'task' . $data['task_id'])) . "\n\n\n"; break; case NOTIFY_ANON_TASK: $body .= L('thankyouforbug') . "\n\n"; $body .= CreateURL(array('details', 'task' . $data['task_id']), array('task_token' => $data['token'])) . "\n\n"; break; case NOTIFY_PW_CHANGE: $body = L('messagefrom') . $data[0] . "\n\n"; $body .= L('magicurlmessage') . " \n"; $body .= "{$data[0]}index.php?do=lostpw&magic_url={$data['1']}\n"; break; case NOTIFY_NEW_USER: $body = L('messagefrom') . $data[0] . "\n\n"; $body .= L('newuserregistered') . " \n\n"; $body .= L('username') . ': ' . $data[1] . "\n"; $body .= L('realname') . ': ' . $data[2] . "\n"; if ($data[6]) { $body .= L('password') . ': ' . $data[5] . "\n"; } $body .= L('emailaddress') . ': ' . $data[3] . "\n"; if ($data[4]) { $body .= L('jabberid') . ':' . $data[4] . "\n\n"; } break; case NOTIFY_REMINDER: case NOTIFY_DIGEST: $body = $data['message'] . "\n\n"; break; } $body .= L('disclaimer'); return array($subject, $body); }
$_POST["task_id"] = $_POST["taskid"]; } } if (isset($_REQUEST["task_id"])) { $_REQUEST["taskid"] = $_REQUEST["task_id"]; } else { if (isset($_REQUEST["taskid"])) { $_REQUEST["task_id"] = $_REQUEST["taskid"]; } } $db = new Database(); $db->dbOpenFast($conf['database']); $fs = new Flyspray(); // If version number of database and files do not match, run upgrader if (Flyspray::base_version($fs->version) != Flyspray::base_version($fs->prefs['fs_ver'])) { Flyspray::Redirect('setup/upgrade.php'); } if (is_readable(BASEDIR . '/setup/index.php') && strpos($fs->version, 'dev') === false) { die('<div style="text-align:center;padding:20px;font-family:sans-serif;font-size:16px;"> <p>If you are upgrading, please <a href="setup/upgrade.php" style=" margin:2em; background-color: white; border: 1px solid #bbb; border-radius: 4px; box-shadow: 0 1px 1px #ddd; color: #565656; cursor: pointer; display: inline-block; font-family: sans-serif; font-size: 100%;
<?php if (!defined('IN_FS')) { die('Do not access this file directly.'); } # let also project managers allow translation of flyspray if (!$user->perms('manage_project')) { Flyspray::show_error(28); } ob_start(); ?> <style type="text/css"> body{font-size:100%;} pre { margin : 0; } table{border-collapse:collapse;} .progress_bar_container{height:20px;} .progress_bar_container span{font-size:100%;} .progress_bar_container span:first-child{display:inline-block;margin-top:2px;} .overview{margin-left:auto;margin-right:auto;} .overview td, .overview th{border:none;padding:0;} a.button{padding:2px 10px 2px 10px;margin:2px;} table th{text-align:center;} table th, table td { vertical-align:middle; border: 1px solid #ccc; padding: 2px; } tr:hover td, tr:hover th { background : #e0e0e0; } </style> <?php require_once dirname(dirname(__FILE__)) . '/includes/fix.inc.php';
if (!$group_details || $group_details['project_id'] != $proj->id) { Flyspray::show_error(L('groupnotexist')); Flyspray::Redirect(CreateURL('pm', 'groups', $proj->id)); } $page->uses('group_details'); } case 'groups': case 'newuser': case 'newuserbulk': case 'editallusers': $page->assign('groups', Flyspray::ListGroups()); case 'userrequest': $sql = $db->Query("SELECT *\n FROM {admin_requests}\n WHERE request_type = 3 AND project_id = 0 AND resolved_by = 0\n ORDER BY time_submitted ASC"); $page->assign('pendings', $db->fetchAllArray($sql)); case 'newproject': case 'os': case 'prefs': case 'resolution': case 'tasktype': case 'status': case 'version': case 'newgroup': $page->setTitle($fs->prefs['page_title'] . L('admintoolboxlong')); $page->pushTpl('admin.' . $area . '.tpl'); break; case 'translations': require_once BASEDIR . '/scripts/langdiff.php'; break; default: Flyspray::show_error(6); }
// make sure people are not attempting to manually fiddle with projects they are not allowed to play with if (Req::has('project') && Req::val('project') != 0 && !$user->can_view_project(Req::val('project'))) { Flyspray::show_error(L('nopermission')); exit; } if ($show_task = Get::val('show_task')) { // If someone used the 'show task' form, redirect them if (is_numeric($show_task)) { Flyspray::Redirect(CreateURL('details', $show_task)); } else { Flyspray::Redirect($baseurl . '?string=' . $show_task); } } if (Flyspray::requestDuplicated()) { // Check that this page isn't being submitted twice Flyspray::show_error(3); } # handle all forms request that modify data if (Req::has('action')) { # enforcing if the form sent the correct anti csrf token # only allow token by post if (!Post::has('csrftoken')) { die('missingtoken'); } elseif (Post::val('csrftoken') == $_SESSION['csrftoken']) { require_once BASEDIR . '/includes/modify.inc.php'; } else { die('wrongtoken'); } } # start collecting infos for the answer page if ($proj->id && $user->perms('manage_project')) {