예제 #1
0
 public function after_save(Table $table, Record $new_record)
 {
     // Don't save changes to the changes tables.
     if (in_array($table->getName(), self::tableNames())) {
         return false;
     }
     $changesetsTable = $this->db->getTable('changesets', false);
     if (!$changesetsTable || !$changesetsTable->getRecord(self::$currentChangesetId)) {
         throw new \Exception("Failed to open changeset #" . self::$currentChangesetId);
     }
     // Save a change for each changed column.
     foreach ($table->getColumns() as $column) {
         $col_name = $column->isForeignKey() ? $column->getName() . Record::FKTITLE : $column->getName();
         $old_val = is_callable(array($this->oldRecord, $col_name)) ? $this->oldRecord->{$col_name}() : null;
         $new_val = $new_record->{$col_name}();
         if ($new_val == $old_val) {
             // Ignore unchanged columns.
             continue;
         }
         $sql = "INSERT INTO changes SET " . " `changeset` = :changeset, " . " `change_type` = 'field', " . " `table_name` = :table_name, " . " `column_name` = :column_name, " . " `record_ident` = :record_ident, " . " `old_value` = :old_value, " . " `new_value` = :new_value ";
         $data = array('changeset' => self::$currentChangesetId, 'table_name' => $table->getName(), 'column_name' => $column->getName(), 'record_ident' => $new_record->getPrimaryKey(), 'old_value' => $old_val, 'new_value' => $new_val);
         // Save the change record.
         $this->db->query($sql, $data);
     }
     // Close the changeset if required.
     if (!self::$keepChangesetOpen) {
         $this->closeChangeset();
     }
 }
예제 #2
0
 /**
  * Get a Table object.
  *
  * @param string $tableName
  * @return \Tabulate\DB\Table
  * @throws \Exception
  */
 protected function getTable($tableName)
 {
     $table = $this->db->getTable($tableName);
     if ($table === false) {
         http_response_code(404);
         throw new \Exception("Table '" . $tableName . "' not found.");
     }
     return $table;
 }
예제 #3
0
 public function tearDown()
 {
     // Close any still-open changeset.
     $changeTracker = new \Tabulate\DB\ChangeTracker($this->db);
     $changeTracker->closeChangeset();
     // Remove all tables.
     $this->db->query('SET FOREIGN_KEY_CHECKS = 0');
     foreach ($this->db->getTableNames(false) as $tbl) {
         $this->db->query("DROP TABLE IF EXISTS `{$tbl}`");
     }
     $this->db->query('SET FOREIGN_KEY_CHECKS = 1');
     parent::tearDown();
 }
예제 #4
0
 protected function installData(\Tabulate\DB\Database $db)
 {
     $this->write("Confirming existance of administrative user, group, and grant");
     // Can't log changes without a user (admin, in this case). So we create a user manually.
     $pwd = password_hash('admin', PASSWORD_DEFAULT);
     $adminUserData = ['id' => Users::ADMIN, 'name' => 'Admin', 'email' => Config::siteEmail(), 'password' => $pwd];
     $adminSql = "INSERT IGNORE INTO `users` SET `id`=:id, `name`=:name, `email`=:email, `password`=:password";
     $db->query($adminSql, $adminUserData);
     // Then we want to create a second user (anon), but this time recording changes. The change-tracker needs to
     // know about permissions, so before creating the 2nd user that we need to grant permission to admin.
     // Permissions are granted to groups, not users, so we put admin in an admin group first (manually).
     $params2 = ['id' => Groups::ADMINISTRATORS, 'name' => 'Administrators'];
     $db->query("INSERT IGNORE INTO `groups` SET `id`=:id, `name`=:name", $params2);
     $params3 = ['user' => Users::ADMIN, 'group' => Groups::ADMINISTRATORS];
     $db->query("INSERT IGNORE INTO `group_members` SET `user`=:user, `group`=:group", $params3);
     // Now we can grant everything (on everything) to the admin group.
     $db->query("INSERT IGNORE INTO `grants` SET `group`=:group", ['group' => Groups::ADMINISTRATORS]);
     // And finally 'reset' the DB so it knows about the above new records.
     $db->reset();
     // Start tracking changes now that there's a user to attribute it to.
     $db->setCurrentUser(Users::ADMIN);
     $changeTracker = new \Tabulate\DB\ChangeTracker($db);
     $changeTracker->openChangeset('Installation', true);
     // Create remaining default users and groups.
     if (!$db->getTable('users')->getRecord(Users::ANON)) {
         $this->write("Inserting user 'Anonymous'");
         $db->getTable('users')->saveRecord(['id' => Users::ANON, 'name' => 'Anonymous']);
     }
     if (!$db->getTable('groups', false)->getRecord(Groups::GENERAL_PUBLIC)) {
         $this->write("Inserting group 'General Public'");
         $db->getTable('groups', false)->saveRecord(['id' => Groups::GENERAL_PUBLIC, 'name' => 'General Public']);
     }
     // Add Anon user to the General Public group.
     $groupMembers = $db->getTable('group_members', false);
     $groupMembers->addFilter('user', '=', Users::ANON);
     $groupMembers->addFilter('group', '=', Groups::GENERAL_PUBLIC);
     if ($groupMembers->getRecordCount() === 0) {
         $this->write("Adding user 'Anonymous' to group 'General Public'");
         $groupMembers->saveRecord(['group' => Groups::GENERAL_PUBLIC, 'user' => Users::ANON]);
     }
     // Add first report (to list reports).
     if (0 == $db->query("SELECT COUNT(*) FROM `" . Reports::reportsTableName() . "`")->fetchColumn()) {
         // Create the default report, to list all reports.
         $templateString = "<dl>\n" . "{% for report in reports %}\n" . "  <dt><a href='{{baseurl}}/reports/{{report.id}}'>{{report.title}}</a></dt>\n" . "  <dd>{{report.description}}</dd>\n" . "{% endfor %}\n" . "</dl>";
         $sql1 = "INSERT INTO `" . Reports::reportsTableName() . "` SET" . " id          = " . Reports::DEFAULT_REPORT_ID . ", " . " title       = 'Reports', " . " description = 'List of all Reports.'," . " template    = :template;";
         $db->query($sql1, ['template' => $templateString]);
         // And the query for the above report.
         $query = "SELECT * FROM " . Reports::reportsTableName();
         $sql2 = "INSERT INTO `" . Reports::reportSourcesTableName() . "` SET " . " report = " . Reports::DEFAULT_REPORT_ID . "," . " name   = 'reports'," . " query  = :query;";
         $db->query($sql2, ['query' => $query]);
     }
     // Finish up.
     $changeTracker->closeChangeset();
 }
예제 #5
0
 /**
  * Get a list of a table's records' IDs and titles, filtered by
  * `$_GET['term']`, for foreign-key fields. Only used when there are more
  * than N records in a foreign table (otherwise the options are presented in
  * a select list).
  * @param \WP_REST_Request $request The request, with a 'table_name' parameter.
  * @return array
  */
 public function foreign_key_values(\WP_REST_Request $request)
 {
     if (!isset($this->get['term'])) {
         return array();
     }
     $db = new Database($this->wpdb);
     $table = $db->getTable($request->get_param('table_name'));
     if (!$table instanceof Table) {
         return array();
     }
     // First get any exact matches.
     $out = $this->foreign_key_values_build($table, '=', $this->get['term']);
     // Then get any 'contains' matches.
     $out += $this->foreign_key_values_build($table, 'like', '%' . $this->get['term'] . '%');
     return $out;
 }
예제 #6
0
 protected function set_up($args)
 {
     $db = new Database($this->wpdb);
     $this->table = $db->getTable($args['table']);
     // Check that a point column exists.
     $points = $this->table->getColumns('point');
     if (empty($points)) {
         // @TODO Show error.
         return;
     }
     $point_col = array_shift($points);
     $this->point_col_name = $point_col->getName();
     // Apply filters.
     $filter_param = isset($args['filter']) ? $args['filter'] : array();
     $this->table->addFilters($filter_param);
     $this->table->addFilter($this->point_col_name, 'not empty', '');
 }
예제 #7
0
 public function testBasics()
 {
     $db = new Database();
     // Make sure the default records were created.
     $db->setCurrentUser(Users::ADMIN);
     $this->assertEquals(2, $db->getTable('users')->getRecordCount());
     $this->assertEquals(2, $db->getTable('groups')->getRecordCount());
     $this->assertEquals(2, $db->getTable('group_members')->getRecordCount());
     // The anon user can't see anything.
     $db->setCurrentUser(Users::ANON);
     $this->assertEquals(Users::ANON, $db->getCurrentUser());
     $this->assertEmpty($db->getTables());
     // The admin user can see everything.
     $db->setCurrentUser(Users::ADMIN);
     $expectedTables = ['changes', 'changesets', 'grants', 'group_members', 'groups', 'sessions', 'test_table', 'test_types', 'users', 'report_sources', 'reports'];
     $this->assertEquals($expectedTables, $db->getTableNames(), '', 0, 1, true, true);
 }
예제 #8
0
 public function save($args)
 {
     if (!isset($args['schema'])) {
         $url = admin_url('admin.php?page=tabulate_schema');
         wp_redirect($url);
     }
     $db = new Database($this->wpdb);
     $schema = $db->getTable($args['schema']);
     $new_name = $args['schema'];
     if ($schema instanceof Table && !empty($args['new_name'])) {
         $schema->rename($args['new_name']);
         $new_name = $schema->getName();
     }
     $template = new Template('schema.html');
     $template->addNotice('updated', 'Schema updated.');
     $url = admin_url('admin.php?page=tabulate_schema&schema=' . $new_name);
     wp_redirect($url);
 }
예제 #9
0
 /**
  * Get a Template instance based on a given report's template string and
  * populated with all of the report's source queries.
  * @param int $report_id
  * @return \Tabulate\Template
  */
 public function get_template($report_id)
 {
     // Find the report.
     $reports = $this->db->getTable(self::reportsTableName());
     $report = $reports->getRecord($report_id);
     if (!$report) {
         throw new \Exception("Report {$report_id} not found.");
     }
     $template = new \Tabulate\Template(false, $report->template());
     $template->title = $report->title();
     $template->file_extension = $report->file_extension();
     $template->mime_type = $report->mime_type();
     // Populate with source data.
     $sql = "SELECT * FROM `" . self::reportSourcesTableName() . "` WHERE report = " . $report_id;
     $sources = $this->db->query($sql)->fetchAll();
     foreach ($sources as $source) {
         $data = $this->db->query($source->query)->fetchAll();
         $template->{$source->name} = $data;
     }
     // Return the template.
     return $template;
 }
예제 #10
0
 public function delete($args)
 {
     $db = new Database();
     $table = $db->getTable($args['table']);
     $recordIdent = isset($args['ident']) ? $args['ident'] : false;
     if (!$recordIdent) {
         $this->redirect($table->getUrl());
     }
     // Ask for confirmation.
     if (!isset($_POST['confirm_deletion'])) {
         $template = new \Tabulate\Template('record/delete.html');
         $template->table = $table;
         $template->record = $table->getRecord($recordIdent);
         return $template->render();
     }
     // Delete the record.
     try {
         $this->wpdb->query('BEGIN');
         $table->deleteRecord($recordIdent);
         $this->wpdb->query('COMMIT');
     } catch (\Exception $e) {
         $template = $this->getTemplate($table);
         $template->record = $table->getRecord($recordIdent);
         $template->addNotice('error', $e->getMessage());
         return $template->render();
     }
     wp_redirect($table->getUrl());
     exit;
 }