summaryrefslogtreecommitdiff
path: root/js/callbacks
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2019-11-17 20:45:02 +0100
committerAndreas Baumann <mail@andreasbaumann.cc>2019-11-17 20:45:02 +0100
commit8df3db566a3a937b45ebf11adb90d265e6f5e2d4 (patch)
tree4d541098d751d5a9acf8c12f6fb9f308ace066ac /js/callbacks
downloadflyspray-8df3db566a3a937b45ebf11adb90d265e6f5e2d4.tar.xz
initial checking of customized version 1.0rc9
Diffstat (limited to 'js/callbacks')
-rw-r--r--js/callbacks/checkrelated.php20
-rw-r--r--js/callbacks/checksave.php16
-rw-r--r--js/callbacks/deletesearches.php30
-rw-r--r--js/callbacks/gethistory.php69
-rw-r--r--js/callbacks/getpreview.php21
-rw-r--r--js/callbacks/getsearches.php30
-rw-r--r--js/callbacks/quickedit.php170
-rw-r--r--js/callbacks/savesearches.php27
-rw-r--r--js/callbacks/searchnames.php55
-rw-r--r--js/callbacks/searchtask.php43
-rw-r--r--js/callbacks/testemail.php44
-rw-r--r--js/callbacks/usersearch.php45
12 files changed, 570 insertions, 0 deletions
diff --git a/js/callbacks/checkrelated.php b/js/callbacks/checkrelated.php
new file mode 100644
index 0000000..3ce3ee8
--- /dev/null
+++ b/js/callbacks/checkrelated.php
@@ -0,0 +1,20 @@
+<?php
+/*
+ Checks if a related tasks belongs to a different project.
+*/
+
+define('IN_FS', true);
+
+require_once('../../header.php');
+
+$sql = $db->query('SELECT project_id
+ FROM {tasks}
+ WHERE task_id = ?',
+ array(Get::val('related_task')));
+
+$relatedproject = $db->fetchOne($sql);
+
+if (Get::val('project') == $relatedproject || !$relatedproject) {
+ echo 'ok';
+}
+?>
diff --git a/js/callbacks/checksave.php b/js/callbacks/checksave.php
new file mode 100644
index 0000000..a5fd1a4
--- /dev/null
+++ b/js/callbacks/checksave.php
@@ -0,0 +1,16 @@
+<?php
+/*
+ Checks if a task can be saved without danger or not.
+*/
+
+define('IN_FS', true);
+
+require_once('../../header.php');
+
+$res = $db->query('SELECT last_edited_time FROM {tasks} WHERE task_id = ?', array(Get::val('task_id')));
+$last_edit = $db->fetchOne($res);
+
+if (Get::val('time') >= $last_edit) {
+ echo 'ok';
+}
+?>
diff --git a/js/callbacks/deletesearches.php b/js/callbacks/deletesearches.php
new file mode 100644
index 0000000..2ff9e3b
--- /dev/null
+++ b/js/callbacks/deletesearches.php
@@ -0,0 +1,30 @@
+<?php
+/*
+ This script is the AJAX callback that deletes a user's saved search
+*/
+
+define('IN_FS', true);
+
+require_once('../../header.php');
+
+if (Cookie::has('flyspray_userid') && Cookie::has('flyspray_passhash')) {
+ $user = new User(Cookie::val('flyspray_userid'));
+ $user->check_account_ok();
+
+ if( !Post::has('csrftoken') ){
+ http_response_code(428); # 'Precondition Required'
+ die('missingtoken');
+ }elseif( Post::val('csrftoken')==$_SESSION['csrftoken']){
+ # empty
+ }else{
+ http_response_code(412); # 'Precondition Failed'
+ die('wrongtoken');
+ }
+
+ if (!$user->isAnon()) {
+ $db->query('DELETE FROM {searches} WHERE id = ? AND user_id = ?', array(Post::num('id'), $user->id));
+ echo $db->affectedRows();
+ }
+}
+
+?>
diff --git a/js/callbacks/gethistory.php b/js/callbacks/gethistory.php
new file mode 100644
index 0000000..617b992
--- /dev/null
+++ b/js/callbacks/gethistory.php
@@ -0,0 +1,69 @@
+<?php
+/*
+ This script gets the history of a task and
+ returns it for HTML display in a page.
+*/
+
+define('IN_FS', true);
+
+header('Content-type: text/html; charset=utf-8');
+
+require_once('../../header.php');
+require_once('../../includes/events.inc.php');
+
+$csp->emit();
+
+if( !isset($_GET['task_id']) or !is_numeric($_GET['task_id'])){
+ die();
+} else {
+ $task_id = Get::num('task_id');
+}
+
+# recalculate $proj for permission check
+$result = $db->query('SELECT project_id FROM {tasks} WHERE task_id = ?', array($task_id));
+$project_id = $db->fetchOne($result);
+if (!$project_id) {
+ die();
+}
+$proj = new Project($project_id);
+
+// Initialise user
+if (Cookie::has('flyspray_userid') && Cookie::has('flyspray_passhash')) {
+ $user = new User(Cookie::val('flyspray_userid'));
+ $user->check_account_ok();
+} else {
+ $user = new User(0, $proj);
+}
+
+load_translations();
+
+# set project of task asked for and then check permissions based on that
+if ( !($task = Flyspray::getTaskDetails($task_id)) ) {
+ die();
+}
+
+# also check the calculated view task permission in addition to view_history permission
+if (!$user->can_view_task($task) or !$user->perms('view_history')) {
+ die();
+}
+
+if ($details = Get::num('details')) {
+ $details = " AND h.history_id = $details";
+} else {
+ $details = null;
+}
+
+$sql = get_events($task_id, $details);
+$histories = $db->fetchAllArray($sql);
+
+$page = new FSTpl;
+$page->setTheme($proj->prefs['theme_style']);
+$page->uses('histories', 'details');
+if ($details) {
+ event_description($histories[0]); // modifies global variables
+ $page->assign('details_previous', $GLOBALS['details_previous']);
+ $page->assign('details_new', $GLOBALS['details_new']);
+}
+$page->display('details.tabs.history.callback.tpl');
+
+?>
diff --git a/js/callbacks/getpreview.php b/js/callbacks/getpreview.php
new file mode 100644
index 0000000..94d973a
--- /dev/null
+++ b/js/callbacks/getpreview.php
@@ -0,0 +1,21 @@
+<?php
+define('IN_FS', true);
+
+header('Content-type: text/html; charset=utf-8');
+
+$webdir = dirname(dirname(dirname(htmlspecialchars($_SERVER['PHP_SELF'], ENT_QUOTES, 'utf-8'))));
+require_once('../../header.php');
+
+if (Cookie::has('flyspray_userid') && Cookie::has('flyspray_passhash')) {
+ $user = new User(Cookie::val('flyspray_userid'));
+ $user->check_account_ok();
+} else {
+ $user = new User(0, $proj);
+}
+
+# TODO csrftoken checking
+
+
+echo TextFormatter::render(Post::val('text'));
+
+?>
diff --git a/js/callbacks/getsearches.php b/js/callbacks/getsearches.php
new file mode 100644
index 0000000..215d2d8
--- /dev/null
+++ b/js/callbacks/getsearches.php
@@ -0,0 +1,30 @@
+<?php
+/*
+ This script gets the searches of current user and
+ returns it for HTML display in a page.
+*/
+
+define('IN_FS', true);
+
+header('Content-type: text/html; charset=utf-8');
+
+require_once('../../header.php');
+
+// Initialise user
+if (Cookie::has('flyspray_userid') && Cookie::has('flyspray_passhash')) {
+ $user = new User(Cookie::val('flyspray_userid'));
+ $user->check_account_ok();
+} else {
+ $user = new User(0, $proj);
+}
+
+// don't allow anonymous users to access this page at all
+if ($user->isAnon()) {
+ die();
+}
+
+$user->save_search(); # currently used for loading user searches from db into user object ...
+$page = new FSTpl;
+$page->setTheme($proj->prefs['theme_style']);
+$page->display('links.searches.tpl');
+?>
diff --git a/js/callbacks/quickedit.php b/js/callbacks/quickedit.php
new file mode 100644
index 0000000..fda26ea
--- /dev/null
+++ b/js/callbacks/quickedit.php
@@ -0,0 +1,170 @@
+<?php
+
+define('IN_FS', true);
+
+header('Content-type: text/html; charset=utf-8');
+
+require_once('../../header.php');
+global $proj, $fs;
+
+if (Cookie::has('flyspray_userid') && Cookie::has('flyspray_passhash')) {
+ $user = new User(Cookie::val('flyspray_userid'));
+ $user->check_account_ok();
+} else {
+ $user = new User(0, $proj);
+}
+
+// don't allow anonymous users to access this page at all
+if ($user->isAnon()) {
+ die();
+}
+load_translations();
+
+if( !Post::has('csrftoken') ){
+ http_response_code(428); # 'Precondition Required'
+ die('missingtoken');
+} elseif( Post::val('csrftoken')==$_SESSION['csrftoken']){
+ # ok
+} else{
+ http_response_code(412); # 'Precondition Failed'
+ die('wrongtoken');
+}
+
+$task = Flyspray::getTaskDetails(Post::val('task_id'));
+if (!$user->can_edit_task($task)){
+ http_response_code(403); # 'Forbidden'
+ die(L('nopermission'));
+}
+
+# check field for update against allowed dbfields for quickedit.
+# maybe FUTURE: add (dynamic read from database) allowed CUSTOM FIELDS checks for the project and user
+# (if there is urgent request for implementing custom fields into Flyspray
+# and using of tag-feature isn't enough to accomplish - like numbers/dates/timestamps as custom fields)
+$allowedFields=array(
+ 'due_date',
+ 'item_status',
+ 'percent_complete',
+ 'task_type',
+ 'product_category',
+ 'operating_system',
+ 'task_severity',
+ 'task_priority',
+ 'product_version',
+ 'closedby_version'
+);
+if ($proj->prefs['use_effort_tracking'] && $user->perms('track_effort')){
+ $allowedFields[]='estimated_effort';
+}
+
+if (!in_array(Post::val('name'), $allowedFields)){
+ http_response_code(403);
+ die(L('invalidfield'));
+}
+
+$value = Post::val('value');
+
+# check if user is not sending manipulated invalid values
+switch(Post::val('name')){
+ case 'due_date':
+ $value = Flyspray::strtotime(Post::val('value'));
+ $value = intval($value);
+ break;
+
+ case 'estimated_effort':
+ $value = effort::editStringToSeconds(Post::val('value'), $proj->prefs['hours_per_manday'], $proj->prefs['estimated_effort_format']);
+ $value = intval($value);
+ break;
+
+ case 'task_severity':
+ if(!preg_match("/^[1-5]$/", $value)){
+ http_response_code(403);
+ die(L('invalidvalue'));
+ }
+ break;
+
+ case 'task_priority':
+ if(!preg_match("/^[1-6]$/", $value)){
+ http_response_code(403);
+ die(L('invalidvalue'));
+ }
+ break;
+
+ case 'percent_complete':
+ if(!is_numeric($value) || $value<0 || $value>100){
+ http_response_code(403);
+ die(L('invalidvalue'));
+ }
+ break;
+
+ case 'item_status':
+ $res=$db->query('SELECT * FROM {list_status} WHERE (project_id=0 OR project_id=?) AND show_in_list=1 AND status_id=?', array($task['project_id'], $value) );
+ if($db->countRows($res)<1){
+ http_response_code(403);
+ die(L('invalidvalue'));
+ }
+ break;
+
+ case 'task_type':
+ $res=$db->query('SELECT * FROM {list_tasktype} WHERE (project_id=0 OR project_id=?) AND show_in_list=1 AND tasktype_id=?', array($task['project_id'], $value) );
+ if($db->countRows($res)<1){
+ http_response_code(403);
+ die(L('invalidvalue'));
+ }
+ break;
+
+ case 'operating_system':
+ $res=$db->query('SELECT * FROM {list_os} WHERE (project_id=0 OR project_id=?) AND show_in_list=1 AND os_id=?', array($task['project_id'], $value) );
+ if($db->countRows($res)<1){
+ http_response_code(403);
+ die(L('invalidvalue'));
+ }
+ break;
+
+ case 'product_category':
+ $res=$db->query('SELECT * FROM {list_category} WHERE (project_id=0 OR project_id=?) AND show_in_list=1 AND category_id=?', array($task['project_id'], $value) );
+ if($db->countRows($res)<1){
+ http_response_code(403);
+ die(L('invalidvalue'));
+ }
+ break;
+
+ case 'product_version':
+ $res=$db->query('SELECT * FROM {list_version} WHERE (project_id=0 OR project_id=?) AND show_in_list=1 AND version_id=? AND version_tense=2', array($task['project_id'], $value) );
+ if($db->countRows($res)<1){
+ http_response_code(403);
+ die(L('invalidvalue'));
+ }
+ break;
+ case 'closedby_version':
+ $res=$db->query('SELECT * FROM {list_version} WHERE (project_id=0 OR project_id=?) AND show_in_list=1 AND version_id=? AND version_tense=3', array($task['project_id'], $value) );
+ if($db->countRows($res)<1){
+ http_response_code(403);
+ die(L('invalidvalue'));
+ }
+ break;
+ default:
+ http_response_code(403);
+ die(L('invalidfield'));
+ break;
+}
+
+$oldvalue = $task[Post::val('name')];
+
+$time=time();
+$sql = $db->query("UPDATE {tasks} SET ".Post::val('name')." = ?,last_edited_time = ? WHERE task_id = ?", array($value, $time, Post::val('task_id')));
+
+# load $proj again of task with correct project_id for getting active notification types in notification class
+$proj= new Project($task['project_id']);
+
+// Log the changed field in task history
+Flyspray::logEvent($task['task_id'], 3, $value, $oldvalue, Post::val('name'), $time);
+
+// Get the details of the task we just updated to generate the changed-task message
+$new_details_full = Flyspray::getTaskDetails($task['task_id']);
+$changes = Flyspray::compare_tasks($task, $new_details_full);
+if (count($changes) > 0) {
+ $notify = new Notifications;
+ $notify->create(NOTIFY_TASK_CHANGED, $task['task_id'], $changes, null, NOTIFY_BOTH, $proj->prefs['lang_code']);
+}
+
+?>
diff --git a/js/callbacks/savesearches.php b/js/callbacks/savesearches.php
new file mode 100644
index 0000000..e656a0a
--- /dev/null
+++ b/js/callbacks/savesearches.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * This script is the AJAX callback that saves a user's search
+ */
+
+define('IN_FS', true);
+
+require_once('../../header.php');
+
+if (Cookie::has('flyspray_userid') && Cookie::has('flyspray_passhash')) {
+ $user = new User(Cookie::val('flyspray_userid'));
+ $user->check_account_ok();
+
+ if( !Post::has('csrftoken') ){
+ http_response_code(428); # 'Precondition Required'
+ die('missingtoken');
+ }elseif( Post::val('csrftoken')==$_SESSION['csrftoken']){
+ # empty
+ }else{
+ http_response_code(412); # 'Precondition Failed'
+ die('wrongtoken');
+ }
+
+ $user->save_search();
+}
+
+?>
diff --git a/js/callbacks/searchnames.php b/js/callbacks/searchnames.php
new file mode 100644
index 0000000..f696955
--- /dev/null
+++ b/js/callbacks/searchnames.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * This script is the AJAX callback that performs a search
+ * for users, and returns true if the user_name is not given.
+ */
+
+define('IN_FS', true);
+
+header('Content-type: text/html; charset=utf-8');
+
+require_once('../../header.php');
+
+
+if (Cookie::has('flyspray_userid') && Cookie::has('flyspray_passhash')) {
+ $user = new User(Cookie::val('flyspray_userid'));
+ $user->check_account_ok();
+} else {
+ $user = new User(0, $proj);
+}
+
+if ($user->isAnon()) {
+ # at least allow for guests when user registration is enabled, fix FS#2528
+ if( !($user->can_register() or $user->can_self_register()) ){
+ die();
+ }
+}
+
+if (Req::has('name')) {
+ $searchterm = strtolower(Req::val('name'));
+} else {
+ die();
+}
+
+// Get the list of users from the global groups above
+$get_users = $db->query('
+ SELECT count(u.user_name) AS anz_u_user, count(r.user_name) AS anz_r_user
+ FROM {users} u
+ LEFT JOIN {registrations} r ON u.user_name = r.user_name
+ WHERE LOWER(u.user_name) = ? OR LOWER(r.user_name) = ?',
+ array($searchterm, $searchterm)
+);
+
+load_translations();
+
+while ($row = $db->fetchRow($get_users)){
+ if ($row['anz_u_user'] > '0' || $row['anz_r_user'] > '0') {
+ $html = 'false|' . eL('usernametaken');
+ } else {
+ $html = 'true';
+ }
+}
+
+echo $html;
+?>
diff --git a/js/callbacks/searchtask.php b/js/callbacks/searchtask.php
new file mode 100644
index 0000000..47b0241
--- /dev/null
+++ b/js/callbacks/searchtask.php
@@ -0,0 +1,43 @@
+<?php
+define('IN_FS', true);
+require_once('../../header.php');
+
+
+// Require inputs
+if(!Post::has('detail') || !Post::has('summary') || !Post::has('project_id'))
+{
+ return;
+}
+
+
+// Load user profile
+if (Cookie::has('flyspray_userid') && Cookie::has('flyspray_passhash')){
+ $user = new User(Cookie::val('flyspray_userid'));
+ $user->check_account_ok();
+} else {
+ $user = new User(0, $proj);
+}
+
+// Require right to open a task on current project
+if(!$user->can_open_task($proj)){
+ return;
+}
+
+
+// Prepare SQL params
+$params = array(
+ 'project_id' => Post::num('project_id'),
+ 'summary' => "%" . trim(Post::val('summary')) . "%",
+ 'details' => "%" . trim(Post::val('detail')) . "%"
+);
+
+$sql = $db->query('SELECT count(*)
+ FROM {tasks} t
+ WHERE t.project_id = ?
+ AND t.item_summary like ?
+ AND t.detailed_desc like ?',
+ $params);
+$sametask = $db->fetchOne($sql);
+echo $sametask;
+
+?>
diff --git a/js/callbacks/testemail.php b/js/callbacks/testemail.php
new file mode 100644
index 0000000..788a12f
--- /dev/null
+++ b/js/callbacks/testemail.php
@@ -0,0 +1,44 @@
+<?php
+
+define('IN_FS', true);
+
+header('Content-type: text/html; charset=utf-8');
+
+require_once('../../header.php');
+global $proj, $fs;
+
+if (Cookie::has('flyspray_userid') && Cookie::has('flyspray_passhash')) {
+ $user = new User(Cookie::val('flyspray_userid'));
+ $user->check_account_ok();
+} else {
+ $user = new User(0, $proj);
+}
+
+// don't allow anonymous users to access this page at all
+if ($user->isAnon()) {
+ die(L('nopermission'));
+}
+load_translations();
+
+if( !Post::has('csrftoken') ){
+ http_response_code(428); # 'Precondition Required'
+ die('missingtoken');
+}elseif( Post::val('csrftoken')==$_SESSION['csrftoken']){
+ # empty
+}else{
+ http_response_code(412); # 'Precondition Failed'
+ die('wrongtoken');
+}
+if (!$user->perms('is_admin')){
+ http_response_code(403); # 'Forbidden'
+ die(L('nopermission'));
+}
+
+$notify = new Notifications;
+$result=$notify->sendEmail($user->infos['email_address'],'test','testcontent',1);
+
+if($result !=1){
+ http_response_code(406); # 'Not Acceptable'
+}
+echo 'ok';
+?>
diff --git a/js/callbacks/usersearch.php b/js/callbacks/usersearch.php
new file mode 100644
index 0000000..a17833d
--- /dev/null
+++ b/js/callbacks/usersearch.php
@@ -0,0 +1,45 @@
+<?php
+/*
+ This script is the AJAX callback that performs a search
+ for users, and returns them in an ordered list.
+*/
+
+define('IN_FS', true);
+header('Content-type: text/html; charset=utf-8');
+require_once('../../header.php');
+
+if (Cookie::has('flyspray_userid') && Cookie::has('flyspray_passhash')) {
+ $user = new User(Cookie::val('flyspray_userid'));
+ $user->check_account_ok();
+} else {
+ $user = new User(0, $proj);
+}
+
+// don't allow anonymous users to access this page at all
+if ($user->isAnon()) {
+ die();
+}
+$first = reset($_POST);
+if (is_array($first)) {
+ $first = reset($first);
+}
+$searchterm = '%' . $first . '%';
+
+// Get the list of users from the global groups above
+$get_users = $db->query('SELECT real_name, user_name, profile_image
+ FROM {users} u
+ WHERE u.user_name LIKE ? OR u.real_name LIKE ?',
+ array($searchterm, $searchterm), 20);
+
+$html = '<ul class="autocomplete">';
+
+while ($row = $db->fetchRow($get_users)) {
+ $data = array_map(array('Filters','noXSS'), $row);
+ $html .= '<li title="' . $data['real_name'] . '">'.($data['profile_image']!='' ? '<img src="avatars/'.$data['profile_image'].'" />' : '<span class="noavatar"></span>' ). $data['user_name'] . '<span class="informal"> ' . $data['real_name'] . '</span></li>';
+}
+
+$html .= '</ul>';
+
+echo $html;
+
+?>