PageRenderTime 26ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 1ms

/qa-include/db/admin.php

http://github.com/q2a/question2answer
PHP | 692 lines | 327 code | 127 blank | 238 comment | 19 complexity | 1fe064a162ba40852480f8dcc9386088 MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /*
  3. Question2Answer by Gideon Greenspan and contributors
  4. http://www.question2answer.org/
  5. Description: Database access functions which are specific to the admin center
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. More about this license: http://www.question2answer.org/license.php
  15. */
  16. if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
  17. header('Location: ../../');
  18. exit;
  19. }
  20. /**
  21. * Return the current version of MySQL
  22. * @return string
  23. */
  24. function qa_db_mysql_version()
  25. {
  26. return qa_db_read_one_value(qa_db_query_raw('SELECT VERSION()'));
  27. }
  28. /**
  29. * Return the total size in bytes of all relevant tables in the Q2A database
  30. * @return float
  31. */
  32. function qa_db_table_size()
  33. {
  34. if (defined('QA_MYSQL_USERS_PREFIX')) { // check if one of the prefixes is a prefix itself of the other
  35. if (stripos(QA_MYSQL_USERS_PREFIX, QA_MYSQL_TABLE_PREFIX) === 0)
  36. $prefixes = array(QA_MYSQL_TABLE_PREFIX);
  37. elseif (stripos(QA_MYSQL_TABLE_PREFIX, QA_MYSQL_USERS_PREFIX) === 0)
  38. $prefixes = array(QA_MYSQL_USERS_PREFIX);
  39. else
  40. $prefixes = array(QA_MYSQL_TABLE_PREFIX, QA_MYSQL_USERS_PREFIX);
  41. } else
  42. $prefixes = array(QA_MYSQL_TABLE_PREFIX);
  43. $size = 0;
  44. foreach ($prefixes as $prefix) {
  45. $statuses = qa_db_read_all_assoc(qa_db_query_raw(
  46. "SHOW TABLE STATUS LIKE '" . $prefix . "%'"
  47. ));
  48. foreach ($statuses as $status)
  49. $size += $status['Data_length'] + $status['Index_length'];
  50. }
  51. return $size;
  52. }
  53. /**
  54. * Return a count of the number of posts of $type in database.
  55. * Set $fromuser to true to only count non-anonymous posts, false to only count anonymous posts
  56. * @param string|null $type
  57. * @param mixed|null $fromuser
  58. * @return string
  59. */
  60. function qa_db_count_posts($type = null, $fromuser = null)
  61. {
  62. $wheresql = '';
  63. if (isset($type))
  64. $wheresql .= ' WHERE type=' . qa_db_argument_to_mysql($type, true);
  65. if (isset($fromuser))
  66. $wheresql .= (strlen($wheresql) ? ' AND' : ' WHERE') . ' userid ' . ($fromuser ? 'IS NOT' : 'IS') . ' NULL';
  67. return qa_db_read_one_value(qa_db_query_sub(
  68. 'SELECT COUNT(*) FROM ^posts' . $wheresql
  69. ));
  70. }
  71. /**
  72. * Return number of registered users in database.
  73. * @return string
  74. */
  75. function qa_db_count_users()
  76. {
  77. return qa_db_read_one_value(qa_db_query_sub(
  78. 'SELECT COUNT(*) FROM ^users'
  79. ));
  80. }
  81. /**
  82. * Return number of active users in database $table
  83. * @param string $table
  84. * @return string
  85. */
  86. function qa_db_count_active_users($table)
  87. {
  88. switch ($table) {
  89. case 'posts':
  90. case 'uservotes':
  91. case 'userpoints':
  92. break;
  93. default:
  94. qa_fatal_error('qa_db_count_active_users() called for unknown table');
  95. break;
  96. }
  97. return qa_db_read_one_value(qa_db_query_sub(
  98. 'SELECT COUNT(DISTINCT(userid)) FROM ^' . $table
  99. ));
  100. }
  101. /**
  102. * Return number of categories in the database
  103. * @return string
  104. */
  105. function qa_db_count_categories()
  106. {
  107. return qa_db_read_one_value(qa_db_query_sub(
  108. 'SELECT COUNT(*) FROM ^categories'
  109. ));
  110. }
  111. /**
  112. * Return number of questions in the database in $categoryid exactly, and not one of its subcategories
  113. * @param int $categoryid
  114. * @return string
  115. */
  116. function qa_db_count_categoryid_qs($categoryid)
  117. {
  118. return qa_db_read_one_value(qa_db_query_sub(
  119. "SELECT COUNT(*) FROM ^posts WHERE categoryid<=># AND type='Q'",
  120. $categoryid
  121. ));
  122. }
  123. /**
  124. * Return list of postids of visible or queued posts by $userid
  125. * @param mixed $userid
  126. * @return array
  127. */
  128. function qa_db_get_user_visible_postids($userid)
  129. {
  130. return qa_db_read_all_values(qa_db_query_sub(
  131. "SELECT postid FROM ^posts WHERE userid=# AND type IN ('Q', 'A', 'C', 'Q_QUEUED', 'A_QUEUED', 'C_QUEUED')",
  132. $userid
  133. ));
  134. }
  135. /**
  136. * Return list of postids of visible or queued posts from $ip address
  137. * @param string $ip
  138. * @return array
  139. */
  140. function qa_db_get_ip_visible_postids($ip)
  141. {
  142. return qa_db_read_all_values(qa_db_query_sub(
  143. "SELECT postid FROM ^posts WHERE createip=UNHEX($) AND type IN ('Q', 'A', 'C', 'Q_QUEUED', 'A_QUEUED', 'C_QUEUED')",
  144. bin2hex(@inet_pton($ip))
  145. ));
  146. }
  147. /**
  148. * Return an array whose keys contain the $postids which exist, and whose elements contain the number of other posts depending on each one
  149. * @param array $postids
  150. * @return array
  151. */
  152. function qa_db_postids_count_dependents($postids)
  153. {
  154. if (!empty($postids))
  155. return qa_db_read_all_assoc(qa_db_query_sub(
  156. "SELECT postid, COALESCE(childcount, 0) AS count FROM ^posts LEFT JOIN (SELECT parentid, COUNT(*) AS childcount FROM ^posts WHERE parentid IN (#) AND LEFT(type, 1) IN ('A', 'C') GROUP BY parentid) x ON postid=x.parentid WHERE postid IN (#)",
  157. $postids, $postids
  158. ), 'postid', 'count');
  159. else
  160. return array();
  161. }
  162. /**
  163. * Return an array of the (up to) $count most recently created users who are awaiting approval and have not been blocked.
  164. * The array element for each user includes a 'profile' key whose value is an array of non-empty profile fields of the user.
  165. * @param int $count
  166. * @return array
  167. */
  168. function qa_db_get_unapproved_users($count)
  169. {
  170. $results = qa_db_read_all_assoc(qa_db_query_sub(
  171. "SELECT ^users.userid, UNIX_TIMESTAMP(created) AS created, createip, email, handle, flags, title, content FROM ^users LEFT JOIN ^userprofile ON ^users.userid=^userprofile.userid AND LENGTH(content)>0 WHERE level<# AND NOT (flags&#) ORDER BY created DESC LIMIT #",
  172. QA_USER_LEVEL_APPROVED, QA_USER_FLAGS_USER_BLOCKED, $count
  173. ));
  174. $users = array();
  175. foreach ($results as $result) {
  176. $userid = $result['userid'];
  177. if (!isset($users[$userid])) {
  178. $users[$result['userid']] = $result;
  179. $users[$result['userid']]['profile'] = array();
  180. unset($users[$userid]['title']);
  181. unset($users[$userid]['content']);
  182. }
  183. if (isset($result['title']) && isset($result['content']))
  184. $users[$userid]['profile'][$result['title']] = $result['content'];
  185. }
  186. return $users;
  187. }
  188. /**
  189. * Return whether there are any blobs whose content has been stored as a file on disk
  190. * @return bool
  191. */
  192. function qa_db_has_blobs_on_disk()
  193. {
  194. return qa_db_read_one_value(qa_db_query_sub('SELECT blobid FROM ^blobs WHERE content IS NULL LIMIT 1'), true) != null;
  195. }
  196. /**
  197. * Return whether there are any blobs whose content has been stored in the database
  198. * @return bool
  199. */
  200. function qa_db_has_blobs_in_db()
  201. {
  202. return qa_db_read_one_value(qa_db_query_sub('SELECT blobid FROM ^blobs WHERE content IS NOT NULL LIMIT 1'), true) != null;
  203. }
  204. /**
  205. * Return the maximum position of the categories with $parentid
  206. * @param int $parentid
  207. * @return string
  208. */
  209. function qa_db_category_last_pos($parentid)
  210. {
  211. return qa_db_read_one_value(qa_db_query_sub(
  212. 'SELECT COALESCE(MAX(position), 0) FROM ^categories WHERE parentid<=>#',
  213. $parentid
  214. ));
  215. }
  216. /**
  217. * Return how many levels of subcategory there are below $categoryid
  218. * @param int $categoryid
  219. * @return int
  220. */
  221. function qa_db_category_child_depth($categoryid)
  222. {
  223. // This is potentially a very slow query since it counts all the multi-generational offspring of a particular category
  224. // But it's only used for admin purposes when moving a category around so I don't think it's worth making more efficient
  225. // (Incidentally, this could be done by keeping a count for every category of how many generations of offspring it has.)
  226. $result = qa_db_read_one_assoc(qa_db_query_sub(
  227. 'SELECT COUNT(child1.categoryid) AS count1, COUNT(child2.categoryid) AS count2, COUNT(child3.categoryid) AS count3 FROM ^categories AS child1 LEFT JOIN ^categories AS child2 ON child2.parentid=child1.categoryid LEFT JOIN ^categories AS child3 ON child3.parentid=child2.categoryid WHERE child1.parentid=#;', // requires QA_CATEGORY_DEPTH=4
  228. $categoryid
  229. ));
  230. for ($depth = QA_CATEGORY_DEPTH - 1; $depth >= 1; $depth--)
  231. if ($result['count' . $depth])
  232. return $depth;
  233. return 0;
  234. }
  235. /**
  236. * Create a new category with $parentid, $title (=name) and $tags (=slug) in the database
  237. * @param int $parentid
  238. * @param string $title
  239. * @param string $tags
  240. * @return int
  241. */
  242. function qa_db_category_create($parentid, $title, $tags)
  243. {
  244. $lastpos = (int)qa_db_category_last_pos($parentid);
  245. qa_db_query_sub(
  246. 'INSERT INTO ^categories (parentid, title, tags, position) VALUES (#, $, $, #)',
  247. $parentid, $title, $tags, $lastpos + 1
  248. );
  249. $categoryid = qa_db_last_insert_id();
  250. qa_db_categories_recalc_backpaths($categoryid);
  251. return $categoryid;
  252. }
  253. /**
  254. * Recalculate the backpath columns for all categories from $firstcategoryid to $lastcategoryid (if specified)
  255. * @param int $firstcategoryid
  256. * @param int|null $lastcategoryid
  257. */
  258. function qa_db_categories_recalc_backpaths($firstcategoryid, $lastcategoryid = null)
  259. {
  260. if (!isset($lastcategoryid))
  261. $lastcategoryid = $firstcategoryid;
  262. qa_db_query_sub(
  263. "UPDATE ^categories AS x, (SELECT cat1.categoryid, CONCAT_WS('/', cat1.tags, cat2.tags, cat3.tags, cat4.tags) AS backpath FROM ^categories AS cat1 LEFT JOIN ^categories AS cat2 ON cat1.parentid=cat2.categoryid LEFT JOIN ^categories AS cat3 ON cat2.parentid=cat3.categoryid LEFT JOIN ^categories AS cat4 ON cat3.parentid=cat4.categoryid WHERE cat1.categoryid BETWEEN # AND #) AS a SET x.backpath=a.backpath WHERE x.categoryid=a.categoryid",
  264. $firstcategoryid, $lastcategoryid // requires QA_CATEGORY_DEPTH=4
  265. );
  266. }
  267. /**
  268. * Set the name of $categoryid to $title and its slug to $tags in the database
  269. * @param int $categoryid
  270. * @param string $title
  271. * @param string $tags
  272. */
  273. function qa_db_category_rename($categoryid, $title, $tags)
  274. {
  275. qa_db_query_sub(
  276. 'UPDATE ^categories SET title=$, tags=$ WHERE categoryid=#',
  277. $title, $tags, $categoryid
  278. );
  279. qa_db_categories_recalc_backpaths($categoryid); // may also require recalculation of its offspring's backpaths
  280. }
  281. /**
  282. * Set the content (=description) of $categoryid to $content
  283. * @param int $categoryid
  284. * @param string $content
  285. */
  286. function qa_db_category_set_content($categoryid, $content)
  287. {
  288. qa_db_query_sub(
  289. 'UPDATE ^categories SET content=$ WHERE categoryid=#',
  290. $content, $categoryid
  291. );
  292. }
  293. /**
  294. * Return the parentid of $categoryid
  295. * @param int $categoryid
  296. * @return string
  297. */
  298. function qa_db_category_get_parent($categoryid)
  299. {
  300. return qa_db_read_one_value(qa_db_query_sub(
  301. 'SELECT parentid FROM ^categories WHERE categoryid=#',
  302. $categoryid
  303. ));
  304. }
  305. /**
  306. * Move the category $categoryid into position $newposition under its parent
  307. * @param int $categoryid
  308. * @param int $newposition
  309. */
  310. function qa_db_category_set_position($categoryid, $newposition)
  311. {
  312. qa_db_ordered_move('categories', 'categoryid', $categoryid, $newposition,
  313. qa_db_apply_sub('parentid<=>#', array(qa_db_category_get_parent($categoryid))));
  314. }
  315. /**
  316. * Set the parent of $categoryid to $newparentid, placing it in last position (doesn't do necessary recalculations)
  317. * @param int $categoryid
  318. * @param string $newparentid
  319. */
  320. function qa_db_category_set_parent($categoryid, $newparentid)
  321. {
  322. $oldparentid = qa_db_category_get_parent($categoryid);
  323. if (strcmp($oldparentid, $newparentid)) { // if we're changing parent, move to end of old parent, then end of new parent
  324. $lastpos = qa_db_category_last_pos($oldparentid);
  325. qa_db_ordered_move('categories', 'categoryid', $categoryid, $lastpos, qa_db_apply_sub('parentid<=>#', array($oldparentid)));
  326. $lastpos = (int)qa_db_category_last_pos($newparentid);
  327. qa_db_query_sub(
  328. 'UPDATE ^categories SET parentid=#, position=# WHERE categoryid=#',
  329. $newparentid, $lastpos + 1, $categoryid
  330. );
  331. }
  332. }
  333. /**
  334. * Change the categoryid of any posts with (exact) $categoryid to $reassignid
  335. * @param int $categoryid
  336. * @param int $reassignid
  337. */
  338. function qa_db_category_reassign($categoryid, $reassignid)
  339. {
  340. qa_db_query_sub('UPDATE ^posts SET categoryid=# WHERE categoryid<=>#', $reassignid, $categoryid);
  341. }
  342. /**
  343. * Delete the category $categoryid in the database
  344. * @param int $categoryid
  345. */
  346. function qa_db_category_delete($categoryid)
  347. {
  348. qa_db_ordered_delete('categories', 'categoryid', $categoryid,
  349. qa_db_apply_sub('parentid<=>#', array(qa_db_category_get_parent($categoryid))));
  350. }
  351. /**
  352. * Return the categoryid for the category with parent $parentid and $slug
  353. * @param int $parentid
  354. * @param string $slug
  355. * @return string|null
  356. */
  357. function qa_db_category_slug_to_id($parentid, $slug)
  358. {
  359. return qa_db_read_one_value(qa_db_query_sub(
  360. 'SELECT categoryid FROM ^categories WHERE parentid<=># AND tags=$',
  361. $parentid, $slug
  362. ), true);
  363. }
  364. /**
  365. * Create a new custom page (or link) in the database
  366. * @param string $title
  367. * @param int $flags
  368. * @param string $tags
  369. * @param string $heading
  370. * @param string $content
  371. * @param int|null $permit
  372. * @return string
  373. */
  374. function qa_db_page_create($title, $flags, $tags, $heading, $content, $permit = null)
  375. {
  376. $position = qa_db_read_one_value(qa_db_query_sub('SELECT 1+COALESCE(MAX(position), 0) FROM ^pages'));
  377. qa_db_query_sub(
  378. 'INSERT INTO ^pages (title, nav, flags, permit, tags, heading, content, position) VALUES ($, \'\', #, #, $, $, $, #)',
  379. $title, $flags, $permit, $tags, $heading, $content, $position
  380. );
  381. return qa_db_last_insert_id();
  382. }
  383. /**
  384. * Set the fields of $pageid to the values provided in the database
  385. * @param int $pageid
  386. * @param string $title
  387. * @param int $flags
  388. * @param string $tags
  389. * @param string $heading
  390. * @param string $content
  391. * @param int|null $permit
  392. */
  393. function qa_db_page_set_fields($pageid, $title, $flags, $tags, $heading, $content, $permit = null)
  394. {
  395. qa_db_query_sub(
  396. 'UPDATE ^pages SET title=$, flags=#, permit=#, tags=$, heading=$, content=$ WHERE pageid=#',
  397. $title, $flags, $permit, $tags, $heading, $content, $pageid
  398. );
  399. }
  400. /**
  401. * Move the page $pageid into navigation menu $nav and position $newposition in the database
  402. * @param int $pageid
  403. * @param string $nav
  404. * @param int $newposition
  405. */
  406. function qa_db_page_move($pageid, $nav, $newposition)
  407. {
  408. qa_db_query_sub(
  409. 'UPDATE ^pages SET nav=$ WHERE pageid=#',
  410. $nav, $pageid
  411. );
  412. qa_db_ordered_move('pages', 'pageid', $pageid, $newposition);
  413. }
  414. /**
  415. * Delete the page $pageid in the database
  416. * @param int $pageid
  417. */
  418. function qa_db_page_delete($pageid)
  419. {
  420. qa_db_ordered_delete('pages', 'pageid', $pageid);
  421. }
  422. /**
  423. * Move the entity identified by $idcolumn=$id into position $newposition (within optional $conditionsql) in $table in the database
  424. * @param string $table
  425. * @param string $idcolumn
  426. * @param string $id
  427. * @param int $newposition
  428. * @param string|null $conditionsql
  429. */
  430. function qa_db_ordered_move($table, $idcolumn, $id, $newposition, $conditionsql = null)
  431. {
  432. $andsql = isset($conditionsql) ? (' AND ' . $conditionsql) : '';
  433. qa_db_query_sub('LOCK TABLES ^' . $table . ' WRITE');
  434. $oldposition = qa_db_read_one_value(qa_db_query_sub('SELECT position FROM ^' . $table . ' WHERE ' . $idcolumn . '=#' . $andsql, $id));
  435. if ($newposition != $oldposition) {
  436. $lastposition = qa_db_read_one_value(qa_db_query_sub('SELECT MAX(position) FROM ^' . $table . ' WHERE TRUE' . $andsql));
  437. $newposition = max(1, min($newposition, $lastposition)); // constrain it to within range
  438. // move it temporarily off the top because we have a unique key on the position column
  439. qa_db_query_sub('UPDATE ^' . $table . ' SET position=# WHERE ' . $idcolumn . '=#' . $andsql, 1 + $lastposition, $id);
  440. if ($newposition < $oldposition)
  441. qa_db_query_sub('UPDATE ^' . $table . ' SET position=position+1 WHERE position BETWEEN # AND #' . $andsql . ' ORDER BY position DESC', $newposition, $oldposition);
  442. else
  443. qa_db_query_sub('UPDATE ^' . $table . ' SET position=position-1 WHERE position BETWEEN # AND #' . $andsql . ' ORDER BY position', $oldposition, $newposition);
  444. qa_db_query_sub('UPDATE ^' . $table . ' SET position=# WHERE ' . $idcolumn . '=#' . $andsql, $newposition, $id);
  445. }
  446. qa_db_query_sub('UNLOCK TABLES');
  447. }
  448. /**
  449. * Delete the entity identified by $idcolumn=$id (and optional $conditionsql) in $table in the database
  450. * @param string $table
  451. * @param string $idcolumn
  452. * @param string $id
  453. * @param string|null $conditionsql
  454. */
  455. function qa_db_ordered_delete($table, $idcolumn, $id, $conditionsql = null)
  456. {
  457. $andsql = isset($conditionsql) ? (' AND ' . $conditionsql) : '';
  458. qa_db_query_sub('LOCK TABLES ^' . $table . ' WRITE');
  459. $oldposition = qa_db_read_one_value(qa_db_query_sub('SELECT position FROM ^' . $table . ' WHERE ' . $idcolumn . '=#' . $andsql, $id));
  460. qa_db_query_sub('DELETE FROM ^' . $table . ' WHERE ' . $idcolumn . '=#' . $andsql, $id);
  461. qa_db_query_sub('UPDATE ^' . $table . ' SET position=position-1 WHERE position>#' . $andsql . ' ORDER BY position', $oldposition);
  462. qa_db_query_sub('UNLOCK TABLES');
  463. }
  464. /**
  465. * Create a new user field with (internal) tag $title, label $content, $flags and $permit in the database.
  466. * @param string $title
  467. * @param string $content
  468. * @param int $flags
  469. * @param int|null $permit
  470. * @return string
  471. */
  472. function qa_db_userfield_create($title, $content, $flags, $permit = null)
  473. {
  474. $position = qa_db_read_one_value(qa_db_query_sub('SELECT 1+COALESCE(MAX(position), 0) FROM ^userfields'));
  475. qa_db_query_sub(
  476. 'INSERT INTO ^userfields (title, content, position, flags, permit) VALUES ($, $, #, #, #)',
  477. $title, $content, $position, $flags, $permit
  478. );
  479. return qa_db_last_insert_id();
  480. }
  481. /**
  482. * Change the user field $fieldid to have label $content, $flags and $permit in the database (the title column cannot be changed once set)
  483. * @param string $fieldid
  484. * @param string $content
  485. * @param int $flags
  486. * @param int|null $permit
  487. */
  488. function qa_db_userfield_set_fields($fieldid, $content, $flags, $permit = null)
  489. {
  490. qa_db_query_sub(
  491. 'UPDATE ^userfields SET content=$, flags=#, permit=# WHERE fieldid=#',
  492. $content, $flags, $permit, $fieldid
  493. );
  494. }
  495. /**
  496. * Move the user field $fieldid into position $newposition in the database
  497. * @param string $fieldid
  498. * @param int $newposition
  499. */
  500. function qa_db_userfield_move($fieldid, $newposition)
  501. {
  502. qa_db_ordered_move('userfields', 'fieldid', $fieldid, $newposition);
  503. }
  504. /**
  505. * Delete the user field $fieldid in the database
  506. * @param string $fieldid
  507. */
  508. function qa_db_userfield_delete($fieldid)
  509. {
  510. qa_db_ordered_delete('userfields', 'fieldid', $fieldid);
  511. }
  512. /**
  513. * Return the ID of a new widget, to be displayed by the widget module named $title on templates within $tags (comma-separated list)
  514. * @param string $title
  515. * @param string $tags
  516. * @return string
  517. */
  518. function qa_db_widget_create($title, $tags)
  519. {
  520. $position = qa_db_read_one_value(qa_db_query_sub('SELECT 1+COALESCE(MAX(position), 0) FROM ^widgets'));
  521. qa_db_query_sub(
  522. 'INSERT INTO ^widgets (place, position, tags, title) VALUES (\'\', #, $, $)',
  523. $position, $tags, $title
  524. );
  525. return qa_db_last_insert_id();
  526. }
  527. /**
  528. * Set the comma-separated list of templates for $widgetid to $tags
  529. * @param int $widgetid
  530. * @param string $tags
  531. */
  532. function qa_db_widget_set_fields($widgetid, $tags)
  533. {
  534. qa_db_query_sub(
  535. 'UPDATE ^widgets SET tags=$ WHERE widgetid=#',
  536. $tags, $widgetid
  537. );
  538. }
  539. /**
  540. * Move the widget $widgetit into position $position in the database's order, and show it in $place on the page
  541. * @param int $widgetid
  542. * @param string $place
  543. * @param int $newposition
  544. */
  545. function qa_db_widget_move($widgetid, $place, $newposition)
  546. {
  547. qa_db_query_sub(
  548. 'UPDATE ^widgets SET place=$ WHERE widgetid=#',
  549. $place, $widgetid
  550. );
  551. qa_db_ordered_move('widgets', 'widgetid', $widgetid, $newposition);
  552. }
  553. /**
  554. * Delete the widget $widgetid in the database
  555. * @param int $widgetid
  556. */
  557. function qa_db_widget_delete($widgetid)
  558. {
  559. qa_db_ordered_delete('widgets', 'widgetid', $widgetid);
  560. }