QwikClock is an employee time tracking app.
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. <?php
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /**
  6. * Make things happen when buttons are pressed and forms submitted.
  7. */
  8. require_once __DIR__ . "/required.php";
  9. require_once __DIR__ . "/lib/login.php";
  10. if ($VARS['action'] !== "signout") {
  11. dieifnotloggedin();
  12. }
  13. if (account_has_permission($_SESSION['username'], "QWIKCLOCK") == FALSE) {
  14. die("You don't have permission to be here.");
  15. }
  16. /**
  17. * Redirects back to the page ID in $_POST/$_GET['source'] with the given message ID.
  18. * The message will be displayed by the app.
  19. * @param string $msg message ID (see lang/messages.php)
  20. * @param string $arg If set, replaces "{arg}" in the message string when displayed to the user.
  21. */
  22. function returnToSender($msg, $arg = "") {
  23. global $VARS;
  24. if ($arg == "") {
  25. header("Location: app.php?page=" . urlencode($VARS['source']) . "&msg=" . $msg);
  26. } else {
  27. header("Location: app.php?page=" . urlencode($VARS['source']) . "&msg=$msg&arg=$arg");
  28. }
  29. die();
  30. }
  31. switch ($VARS['action']) {
  32. case "punchin":
  33. if ($database->has('punches', ['AND' => ['uid' => $_SESSION['uid'], 'out' => null]])) {
  34. returnToSender("already_in");
  35. }
  36. $shiftid = null;
  37. if ($database->has('assigned_shifts', ['uid' => $_SESSION['uid']])) {
  38. $minclockintime = strtotime("now + 5 minutes");
  39. $shifts = $database->select('shifts', ["[>]assigned_shifts" => ['shiftid' => 'shiftid']], ["shifts.shiftid", "start", "end", "days"], ["AND" => ['uid' => $_SESSION['uid'], 'start[<=]' => date("H:i:s", $minclockintime)]]);
  40. foreach ($shifts as $shift) {
  41. $curday = substr(date("D"), 0, 2);
  42. if (strpos($shift['days'], $curday) === FALSE) {
  43. continue;
  44. }
  45. if (strtotime($shift['end']) >= strtotime($shift['start'])) {
  46. if (strtotime("now") >= strtotime($shift['end'])) {
  47. continue; // shift is already over
  48. }
  49. }
  50. $shiftid = $shift['shiftid'];
  51. }
  52. if (is_null($shiftid)) {
  53. returnToSender("not_assigned_to_work");
  54. }
  55. }
  56. $database->insert('punches', ['uid' => $_SESSION['uid'], 'in' => date("Y-m-d H:i:s"), 'out' => null, 'notes' => '', 'shiftid' => $shiftid]);
  57. returnToSender("punched_in");
  58. case "punchout":
  59. if (!$database->has('punches', ['AND' => ['uid' => $_SESSION['uid'], 'out' => null]])) {
  60. returnToSender("already_out");
  61. }
  62. // Stop active job
  63. $database->update('job_tracking', ['end' => date("Y-m-d H:i:s")], ['AND' => ['uid' => $_SESSION['uid'], 'end' => null]]);
  64. $database->update('punches', ['uid' => $_SESSION['uid'], 'out' => date("Y-m-d H:i:s")], ['out' => null]);
  65. returnToSender("punched_out");
  66. case "gettime":
  67. $out = ["status" => "OK", "time" => date(TIME_FORMAT), "date" => date(LONG_DATE_FORMAT), "seconds" => date("s")];
  68. header('Content-Type: application/json');
  69. exit(json_encode($out));
  70. case "getinoutstatus":
  71. $in = $database->has('punches', ['AND' => ['uid' => $_SESSION['uid'], 'out' => null]]) === TRUE;
  72. $out = ["status" => "OK", "in" => $in];
  73. header('Content-Type: application/json');
  74. exit(json_encode($out));
  75. case "editpunch":
  76. require_once __DIR__ . "/lib/userinfo.php";
  77. if (user_exists($VARS['user'])) {
  78. $uid = getUserByUsername($VARS['user'])['uid'];
  79. } else {
  80. returnToSender("invalid_user");
  81. }
  82. $in = strtotime($VARS['in']);
  83. $out = strtotime($VARS['out']);
  84. if ($in === false) {
  85. returnToSender("invalid_datetime");
  86. }
  87. if ($out === false) {
  88. returnToSender("invalid_datetime");
  89. }
  90. if ($out < $in) {
  91. returnToSender("in_before_out");
  92. }
  93. if (
  94. account_has_permission($_SESSION['username'], "QWIKCLOCK_ADMIN") || (
  95. account_has_permission($_SESSION['username'], "QWIKCLOCK_MANAGE") && isManagerOf($_SESSION['uid'], $uid)
  96. ) || (
  97. account_has_permission($_SESSION['username'], "QWIKCLOCK_EDITSELF") && $_SESSION['uid'] == $uid
  98. )
  99. ) {
  100. $data = [
  101. "uid" => $uid,
  102. "in" => date('Y-m-d H:i:s', $in),
  103. "out" => date('Y-m-d H:i:s', $out),
  104. "notes" => $VARS['notes']
  105. ];
  106. if ($database->has("punches", ["punchid" => $VARS['punchid']])) {
  107. $database->update("punches", $data, ["punchid" => $VARS['punchid']]);
  108. } else {
  109. $database->insert("punches", $data);
  110. }
  111. returnToSender("punch_saved");
  112. } else {
  113. returnToSender("no_permission");
  114. }
  115. case "deletepunch":
  116. require_once __DIR__ . "/lib/userinfo.php";
  117. if (!$database->has("punches", ["punchid" => $VARS['punchid']])) {
  118. returnToSender("invalid_parameters");
  119. }
  120. $pid = $VARS['punchid'];
  121. $uid = $database->get("punches", "uid", ["punchid" => $pid]);
  122. if (
  123. account_has_permission($_SESSION['username'], "QWIKCLOCK_ADMIN") || (
  124. account_has_permission($_SESSION['username'], "QWIKCLOCK_MANAGE") && isManagerOf($_SESSION['uid'], $uid)
  125. ) || (
  126. account_has_permission($_SESSION['username'], "QWIKCLOCK_EDITSELF") && $_SESSION['uid'] == $uid
  127. )
  128. ) {
  129. $database->delete("punches", ["punchid" => $VARS['punchid']]);
  130. returnToSender("punch_deleted");
  131. } else {
  132. returnToSender("no_permission");
  133. }
  134. case "editshift":
  135. if (account_has_permission($_SESSION['username'], "QWIKCLOCK_ADMIN")) {
  136. $valid_daycodes = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
  137. $name = htmlentities($VARS['shiftname']);
  138. $start = $VARS['start'];
  139. $end = $VARS['end'];
  140. $days = $VARS['days'];
  141. $startepoch = strtotime($start);
  142. if ($startepoch === false) {
  143. returnToSender("invalid_time");
  144. }
  145. $startformatted = date("H:i:s", $startepoch);
  146. $endepoch = strtotime($end);
  147. if ($endepoch === false) {
  148. returnToSender("invalid_time");
  149. }
  150. $endformatted = date("H:i:s", $endepoch);
  151. // Parse days into string, validating along the way
  152. $daystring = "";
  153. foreach ($days as $d) {
  154. if (in_array($d, $valid_daycodes)) {
  155. if (strpos($daystring, $d) === FALSE) {
  156. $daystring .= $d;
  157. }
  158. }
  159. }
  160. if (is_empty($VARS['shiftid'])) {
  161. if ($database->has('shifts', ['shiftname' => $name])) {
  162. returnToSender("shift_name_used");
  163. }
  164. $database->insert('shifts', ["shiftname" => $name, "start" => $startformatted, "end" => $endformatted, "days" => $daystring]);
  165. returnToSender("shift_added");
  166. } else if ($database->has('shifts', ['shiftid' => $VARS['shiftid']])) {
  167. $database->update('shifts', ["shiftname" => $name, "start" => $startformatted, "end" => $endformatted, "days" => $daystring], ["shiftid" => $VARS['shiftid']]);
  168. returnToSender("shift_saved");
  169. } else {
  170. returnToSender("invalid_shiftid");
  171. }
  172. } else {
  173. returnToSender("no_permission");
  174. }
  175. case "deleteshift":
  176. if (!$database->has('shifts', ['shiftid' => $VARS['shiftid']])) {
  177. returnToSender("invalid_shiftid");
  178. }
  179. if (account_has_permission($_SESSION['username'], "QWIKCLOCK_ADMIN")) {
  180. if ($database->has('assigned_shifts', ['shiftid' => $VARS['shiftid']])) {
  181. returnToSender('shift_has_users');
  182. }
  183. $database->delete('shifts', ['shiftid' => $VARS['shiftid']]);
  184. returnToSender("shift_deleted");
  185. } else {
  186. returnToSender("no_permission");
  187. }
  188. case "assignshift":
  189. if (!account_has_permission($_SESSION['username'], "QWIKCLOCK_MANAGE") && !account_has_permission($_SESSION['username'], "QWIKCLOCK_ADMIN")) {
  190. returnToSender("no_permission");
  191. }
  192. if (!$database->has('shifts', ['shiftid' => $VARS['shift']])) {
  193. returnToSender("invalid_shiftid");
  194. }
  195. $already_assigned = $database->select('assigned_shifts', 'uid', ['shiftid' => $VARS['shift']]);
  196. require_once __DIR__ . "/lib/userinfo.php";
  197. $managedusers = getManagedUsernames($_SESSION['uid']);
  198. $manageduids = getManagedUIDs($_SESSION['uid']);
  199. foreach ($VARS['users'] as $u) {
  200. if (!user_exists($u)) {
  201. returnToSender("user_not_exists", htmlentities($u));
  202. }
  203. $uid = getUserByUsername($u)['uid'];
  204. if (!account_has_permission($_SESSION['username'], "QWIKCLOCK_ADMIN")) {
  205. if (!in_array($u, $managedusers) && !in_array($uid, $already_assigned)) {
  206. returnToSender("you_arent_my_supervisor", htmlentities($u));
  207. }
  208. }
  209. if (!in_array($uid, $already_assigned)) {
  210. $database->insert('assigned_shifts', ['uid' => $uid, 'shiftid' => $VARS['shift']]);
  211. }
  212. $already_assigned = array_diff($already_assigned, [$uid]); // Remove user from old list
  213. }
  214. // $already_assigned now only has removed users
  215. $removefailed = false;
  216. foreach ($already_assigned as $uid) {
  217. if (!account_has_permission($_SESSION['username'], "QWIKCLOCK_ADMIN")) {
  218. if (!in_array($uid, $manageduids)) {
  219. $removefailed = true;
  220. continue;
  221. }
  222. }
  223. $database->delete('assigned_shifts', ["AND" => ['uid' => $uid, 'shiftid' => $VARS['shift']]]);
  224. }
  225. returnToSender($removefailed ? "shift_assigned_removefailed" : "shift_assigned");
  226. break;
  227. case "setjob":
  228. if ($database->count("job_groups") > 0) {
  229. require_once __DIR__ . "/lib/userinfo.php";
  230. $groups = getGroupsByUID($_SESSION['uid']);
  231. $gids = [];
  232. foreach ($groups as $g) {
  233. $gids[] = $g['id'];
  234. }
  235. $job = $database->has('jobs', ['[>]job_groups' => ['jobid']], ["AND" => ["OR" => ['groupid' => $gids, 'groupid #-1' => -1], 'deleted' => 0, 'jobs.jobid' => $VARS['job']]]);
  236. } else {
  237. $job = $database->has('jobs', 'jobid', ['jobid' => $VARS['job']]);
  238. }
  239. if ($job) {
  240. // Stop other jobs
  241. $database->update('job_tracking', ['end' => date("Y-m-d H:i:s")], ['AND' => ['uid' => $_SESSION['uid'], 'end' => null]]);
  242. $database->insert('job_tracking', ['uid' => $_SESSION['uid'], 'jobid' => $VARS['job'], 'start' => date("Y-m-d H:i:s")]);
  243. returnToSender("job_changed");
  244. } else if ($VARS['job'] == "-1") {
  245. $database->update('job_tracking', ['end' => date("Y-m-d H:i:s")], ['AND' => ['uid' => $_SESSION['uid'], 'end' => null]]);
  246. returnToSender("job_changed");
  247. } else {
  248. returnToSender("job_invalid");
  249. }
  250. break;
  251. case "editjob":
  252. if (account_has_permission($_SESSION['username'], "QWIKCLOCK_ADMIN")) {
  253. $name = htmlentities($VARS['jobname']);
  254. $code = $VARS['jobcode'];
  255. $color = $VARS['color'];
  256. $groups = $VARS['groups'];
  257. if (is_empty($VARS['jobid'])) {
  258. if ($database->has('jobs', ['jobname' => $name])) {
  259. returnToSender("job_name_used");
  260. }
  261. $database->insert('jobs', ["jobname" => $name, "jobcode" => $code, "color" => $color]);
  262. $jobid = $database->id();
  263. $database->delete('job_groups', ['jobid' => $jobid]);
  264. foreach ($groups as $g) {
  265. $database->insert('job_groups', ['jobid' => $jobid, 'groupid' => $g]);
  266. }
  267. returnToSender("job_added");
  268. } else if ($database->has('jobs', ['jobid' => $VARS['jobid']])) {
  269. $database->update('jobs', ["jobname" => $name, "jobcode" => $code, "color" => $color], ["jobid" => $VARS['jobid']]);
  270. $database->delete('job_groups', ['jobid' => $VARS['jobid']]);
  271. foreach ($groups as $g) {
  272. $database->insert('job_groups', ['jobid' => $VARS['jobid'], 'groupid' => $g]);
  273. }
  274. returnToSender("job_saved");
  275. } else {
  276. returnToSender("invalid_jobid");
  277. }
  278. } else {
  279. returnToSender("no_permission");
  280. }
  281. break;
  282. case "deletejob":
  283. if (account_has_permission($_SESSION['username'], "QWIKCLOCK_ADMIN")) {
  284. if (is_empty($VARS['jobid'])) {
  285. returnToSender("invalid_jobid");
  286. } else if ($database->has('jobs', ['jobid' => $VARS['jobid']])) {
  287. $database->update('jobs', ["deleted" => 1], ["jobid" => $VARS['jobid']]);
  288. returnToSender("job_deleted");
  289. } else {
  290. returnToSender("invalid_jobid");
  291. }
  292. } else {
  293. returnToSender("no_permission");
  294. }
  295. break;
  296. case "editjobhistory":
  297. require_once __DIR__ . "/lib/userinfo.php";
  298. if ($database->has('job_tracking', ['id' => $VARS['jobid']])) {
  299. $uid = $database->get('job_tracking', 'uid', ['id' => $VARS['jobid']]);
  300. } else {
  301. returnToSender("invalid_parameters");
  302. }
  303. if (!$database->has("jobs", ['jobid' => $VARS['job']])) {
  304. returnToSender("invalid_jobid");
  305. }
  306. $start = strtotime($VARS['start']);
  307. $end = strtotime($VARS['end']);
  308. if ($start === false) {
  309. returnToSender("invalid_datetime");
  310. }
  311. if ($end === false) {
  312. returnToSender("invalid_datetime");
  313. }
  314. if ($end < $start) {
  315. returnToSender("in_before_out");
  316. }
  317. if (
  318. account_has_permission($_SESSION['username'], "QWIKCLOCK_ADMIN") || (
  319. account_has_permission($_SESSION['username'], "QWIKCLOCK_MANAGE") && isManagerOf($_SESSION['uid'], $uid)
  320. ) || (
  321. account_has_permission($_SESSION['username'], "QWIKCLOCK_EDITSELF") && $_SESSION['uid'] == $uid
  322. )
  323. ) {
  324. $data = [
  325. "jobid" => $VARS['job'],
  326. "start" => date('Y-m-d H:i:s', $start),
  327. "end" => date('Y-m-d H:i:s', $end)
  328. ];
  329. $database->update("job_tracking", $data, ["id" => $VARS['jobid']]);
  330. returnToSender("job_saved");
  331. } else {
  332. returnToSender("no_permission");
  333. }
  334. case "deletejobhistory":
  335. require_once __DIR__ . "/lib/userinfo.php";
  336. if ($database->has('job_tracking', ['id' => $VARS['jobid']])) {
  337. $uid = $database->get('job_tracking', 'uid', ['id' => $VARS['jobid']]);
  338. } else {
  339. returnToSender("invalid_parameters");
  340. }
  341. if (
  342. account_has_permission($_SESSION['username'], "QWIKCLOCK_ADMIN") || (
  343. account_has_permission($_SESSION['username'], "QWIKCLOCK_MANAGE") && isManagerOf($_SESSION['uid'], $uid)
  344. ) || (
  345. account_has_permission($_SESSION['username'], "QWIKCLOCK_EDITSELF") && $_SESSION['uid'] == $uid
  346. )
  347. ) {
  348. $database->delete("job_tracking", ["id" => $VARS['jobid']]);
  349. returnToSender("job_deleted");
  350. } else {
  351. returnToSender("no_permission");
  352. }
  353. case "autocomplete_user":
  354. header("Content-Type: application/json");
  355. $client = new GuzzleHttp\Client();
  356. $response = $client
  357. ->request('POST', PORTAL_API, [
  358. 'form_params' => [
  359. 'key' => PORTAL_KEY,
  360. 'action' => "usersearch",
  361. 'search' => $VARS['q']
  362. ]
  363. ]);
  364. if ($response->getStatusCode() != 200) {
  365. exit("[]");
  366. }
  367. $resp = json_decode($response->getBody(), TRUE);
  368. if ($resp['status'] == "OK") {
  369. if (!account_has_permission($_SESSION['username'], "QWIKCLOCK_ADMIN")) {
  370. require_once __DIR__ . "/lib/userinfo.php";
  371. $managed = getManagedUIDs($_SESSION['uid']);
  372. $result = $resp['result'];
  373. for ($i = 0; $i < count($result); $i++) {
  374. if (!in_array($result[$i]['uid'], $managed)) {
  375. $result[$i]['managed'] = 0;
  376. }
  377. }
  378. exit(json_encode($result));
  379. } else {
  380. exit(json_encode($resp['result']));
  381. }
  382. } else {
  383. exit("[]");
  384. }
  385. break;
  386. case "signout":
  387. session_destroy();
  388. header('Location: index.php');
  389. die("Logged out.");
  390. }