From 4985077a9ef50a24e4808907d5fcc6b62863b699 Mon Sep 17 00:00:00 2001 From: Stephen Vickers Date: Wed, 10 Jun 2020 10:46:30 +0100 Subject: [PATCH] Bug fixes Improve saving of resource links when context ID is not always passed in messages. Fix processing of share keys. --- src/DataConnector/DataConnector_mysql.php | 20 ++++--- src/DataConnector/DataConnector_mysqli.php | 18 +++--- src/DataConnector/DataConnector_oci.php | 48 ++++++++++------ src/DataConnector/DataConnector_pdo.php | 55 ++++++++++++------- src/DataConnector/DataConnector_pg.php | 20 ++++--- src/DataConnector/DataConnector_sqlsrv.php | 35 +++++++----- src/ResourceLink.php | 27 +++++++-- src/ResourceLinkShareKey.php | 3 +- src/ToolProvider.php | 64 +++++++++++----------- 9 files changed, 181 insertions(+), 109 deletions(-) diff --git a/src/DataConnector/DataConnector_mysql.php b/src/DataConnector/DataConnector_mysql.php index 7d93018..4383af9 100644 --- a/src/DataConnector/DataConnector_mysql.php +++ b/src/DataConnector/DataConnector_mysql.php @@ -485,10 +485,13 @@ public function loadResourceLink($resourceLink) "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' ' . 'WHERE (resource_link_pk = %d)', $resourceLink->getRecordId()); } elseif (!is_null($resourceLink->getContext())) { - $sql = sprintf('SELECT resource_link_pk, context_pk, consumer_pk, title, lti_resource_link_id, settings, primary_resource_link_pk, share_approved, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' ' . - 'WHERE (context_pk = %d) AND (lti_resource_link_id = %s)', $resourceLink->getContext()->getRecordId(), - $this->escape($resourceLink->getId())); + $sql = sprintf('SELECT r.resource_link_pk, r.context_pk, r.consumer_pk, r.title, r.lti_resource_link_id, r.settings, r.primary_resource_link_pk, r.share_approved, r.created, r.updated ' . + "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' r ' . + 'WHERE (r.lti_resource_link_id = %s) AND ((r.context_pk = %d) OR (r.consumer_pk IN (' . + 'SELECT c.consumer_pk ' . + "FROM {$this->dbTableNamePrefix}" . static::CONTEXT_TABLE_NAME . ' c ' . + 'WHERE (c.context_pk = %d))))', $this->escape($resourceLink->getId()), $resourceLink->getContext()->getRecordId(), + $resourceLink->getContext()->getRecordId()); } else { $sql = sprintf('SELECT r.resource_link_pk, r.context_pk, r.consumer_pk, r.title, r.lti_resource_link_id, r.settings, r.primary_resource_link_pk, r.share_approved, r.created, r.updated ' . "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' r LEFT OUTER JOIN ' . @@ -587,9 +590,9 @@ public function saveResourceLink($resourceLink) $this->escape($now), $contextId, $id); } else { $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' SET ' . - 'context_pk = %s, title = %s, lti_resource_link_id = %s, settings = %s, ' . + 'context_pk = NULL, title = %s, lti_resource_link_id = %s, settings = %s, ' . 'primary_resource_link_pk = %s, share_approved = %s, updated = %s ' . - 'WHERE (consumer_pk = %s) AND (resource_link_pk = %d)', $contextId, $this->escape($resourceLink->title), + 'WHERE (consumer_pk = %s) AND (resource_link_pk = %d)', $this->escape($resourceLink->title), $this->escape($resourceLink->getId()), $this->escape($settingsValue), $primaryResourceLinkId, $approved, $this->escape($now), $consumerId, $id); } @@ -720,7 +723,9 @@ public function getSharesResourceLink($resourceLink) if ($rsShare) { while ($row = mysql_fetch_object($rsShare)) { $share = new LTI\ResourceLinkShare(); + $share->consumer_name = $row->consumer_name; $share->resourceLinkId = intval($row->resource_link_pk); + $share->title = $row->title; $share->approved = (intval($row->share_approved) === 1); $shares[] = $share; } @@ -808,7 +813,8 @@ public function loadResourceLinkShareKey($shareKey) $rsShareKey = $this->executeQuery($sql); if ($rsShareKey) { $row = mysql_fetch_object($rsShareKey); - if ($row && (intval($row->resource_link_pk) === $shareKey->resourceLinkId)) { + if ($row) { + $shareKey->resourceLinkId = intval($row->resource_link_pk); $shareKey->autoApprove = (intval($row->auto_approve) === 1); $shareKey->expires = strtotime($row->expires); $ok = true; diff --git a/src/DataConnector/DataConnector_mysqli.php b/src/DataConnector/DataConnector_mysqli.php index 96fb2ce..1c5fb8d 100644 --- a/src/DataConnector/DataConnector_mysqli.php +++ b/src/DataConnector/DataConnector_mysqli.php @@ -485,10 +485,13 @@ public function loadResourceLink($resourceLink) "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' ' . 'WHERE (resource_link_pk = %d)', $resourceLink->getRecordId()); } elseif (!is_null($resourceLink->getContext())) { - $sql = sprintf('SELECT resource_link_pk, context_pk, consumer_pk, title, lti_resource_link_id, settings, primary_resource_link_pk, share_approved, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' ' . - 'WHERE (context_pk = %d) AND (lti_resource_link_id = %s)', $resourceLink->getContext()->getRecordId(), - $this->escape($resourceLink->getId())); + $sql = sprintf('SELECT r.resource_link_pk, r.context_pk, r.consumer_pk, r.title, r.lti_resource_link_id, r.settings, r.primary_resource_link_pk, r.share_approved, r.created, r.updated ' . + "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' r ' . + 'WHERE (r.lti_resource_link_id = %s) AND ((r.context_pk = %d) OR (r.consumer_pk IN (' . + 'SELECT c.consumer_pk ' . + "FROM {$this->dbTableNamePrefix}" . static::CONTEXT_TABLE_NAME . ' c ' . + 'WHERE (c.context_pk = %d))))', $this->escape($resourceLink->getId()), $resourceLink->getContext()->getRecordId(), + $resourceLink->getContext()->getRecordId()); } else { $sql = sprintf('SELECT r.resource_link_pk, r.context_pk, r.consumer_pk, r.title, r.lti_resource_link_id, r.settings, r.primary_resource_link_pk, r.share_approved, r.created, r.updated ' . "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' r LEFT OUTER JOIN ' . @@ -587,9 +590,9 @@ public function saveResourceLink($resourceLink) $this->escape($now), $contextId, $id); } else { $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' SET ' . - 'context_pk = %s, title = %s, lti_resource_link_id = %s, settings = %s, ' . + 'context_pk = NULL, title = %s, lti_resource_link_id = %s, settings = %s, ' . 'primary_resource_link_pk = %s, share_approved = %s, updated = %s ' . - 'WHERE (consumer_pk = %s) AND (resource_link_pk = %d)', $contextId, $this->escape($resourceLink->title), + 'WHERE (consumer_pk = %s) AND (resource_link_pk = %d)', $this->escape($resourceLink->title), $this->escape($resourceLink->getId()), $this->escape($settingsValue), $primaryResourceLinkId, $approved, $this->escape($now), $consumerId, $id); } @@ -809,7 +812,8 @@ public function loadResourceLinkShareKey($shareKey) $rsShareKey = $this->executeQuery($sql); if ($rsShareKey) { $row = mysqli_fetch_object($rsShareKey); - if ($row && (intval($row->resource_link_pk) === $shareKey->resourceLinkId)) { + if ($row) { + $shareKey->resourceLinkId = intval($row->resource_link_pk); $shareKey->autoApprove = (intval($row->auto_approve) === 1); $shareKey->expires = strtotime($row->expires); $ok = true; diff --git a/src/DataConnector/DataConnector_oci.php b/src/DataConnector/DataConnector_oci.php index 39f3e6c..efa14c8 100644 --- a/src/DataConnector/DataConnector_oci.php +++ b/src/DataConnector/DataConnector_oci.php @@ -600,14 +600,19 @@ public function loadResourceLink($resourceLink) $id = $resourceLink->getRecordId(); oci_bind_by_name($query, 'id', $id); } elseif (!is_null($resourceLink->getContext())) { - $sql = 'SELECT resource_link_pk, context_pk, consumer_pk, lti_resource_link_id, settings, primary_resource_link_pk, share_approved, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' ' . - 'WHERE (context_pk = :id) AND (lti_resource_link_id = :rlid)'; + $sql = 'SELECT r.resource_link_pk, r.context_pk, r.consumer_pk, r.title, r.lti_resource_link_id, r.settings, r.primary_resource_link_pk, r.share_approved, r.created, r.updated ' . + "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' r ' . + 'WHERE (r.lti_resource_link_id = :rlid) AND ((r.context_pk = :id1) OR (r.consumer_pk IN (' . + 'SELECT c.consumer_pk ' . + "FROM {$this->dbTableNamePrefix}" . static::CONTEXT_TABLE_NAME . ' c ' . + 'WHERE (c.context_pk = :id2)' . + ')))'; $query = oci_parse($this->db, $sql); - $id = $resourceLink->getContext()->getRecordId(); - oci_bind_by_name($query, 'id', $id); $rlid = $resourceLink->getId(); oci_bind_by_name($query, 'rlid', $rlid); + $id = $resourceLink->getContext()->getRecordId(); + oci_bind_by_name($query, 'id1', $id); + oci_bind_by_name($query, 'id2', $id); } else { $sql = 'SELECT r.resource_link_pk, r.context_pk, r.consumer_pk, r.lti_resource_link_id, r.settings, r.primary_resource_link_pk, r.share_approved, r.created, r.updated ' . "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' r LEFT OUTER JOIN ' . @@ -677,17 +682,24 @@ public function loadResourceLink($resourceLink) */ public function saveResourceLink($resourceLink) { + if (is_null($resourceLink->shareApproved)) { + $approved = null; + } elseif ($resourceLink->shareApproved) { + $approved = 1; + } else { + $approved = 0; + } $time = time(); $now = date("{$this->dateFormat} {$this->timeFormat}", $time); $settingsValue = json_encode($resourceLink->getSettings()); if (!is_null($resourceLink->getContext())) { $consumerId = null; - $contextId = strval($resourceLink->getContext()->getRecordId()); + $contextId = $resourceLink->getContext()->getRecordId(); } elseif (!is_null($resourceLink->getContextId())) { $consumerId = null; - $contextId = strval($resourceLink->getContextId()); + $contextId = $resourceLink->getContextId(); } else { - $consumerId = strval($resourceLink->getConsumer()->getRecordId()); + $consumerId = $resourceLink->getConsumer()->getRecordId(); $contextId = null; } if (empty($resourceLink->primaryResourceLinkId)) { @@ -707,7 +719,7 @@ public function saveResourceLink($resourceLink) oci_bind_by_name($query, 'rlid', $rlid); oci_bind_by_name($query, 'settings', $settingsValue); oci_bind_by_name($query, 'prlid', $primaryResourceLinkId); - oci_bind_by_name($query, 'share_approved', $resourceLink->shareApproved); + oci_bind_by_name($query, 'share_approved', $approved); oci_bind_by_name($query, 'created', $now); oci_bind_by_name($query, 'updated', $now); oci_bind_by_name($query, 'pk', $pk); @@ -722,21 +734,20 @@ public function saveResourceLink($resourceLink) oci_bind_by_name($query, 'rlid', $rlid); oci_bind_by_name($query, 'settings', $settingsValue); oci_bind_by_name($query, 'prlid', $primaryResourceLinkId); - oci_bind_by_name($query, 'share_approved', $resourceLink->shareApproved); + oci_bind_by_name($query, 'share_approved', $approved); oci_bind_by_name($query, 'updated', $now); oci_bind_by_name($query, 'id', $id); } else { $sql = "UPDATE {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' SET ' . - 'context_pk = :ctx, lti_resource_link_id = :rlid, settings = :settings, ' . + 'context_pk = NULL, lti_resource_link_id = :rlid, settings = :settings, ' . 'primary_resource_link_pk = :prlid, share_approved = :share_approved, updated = :updated ' . 'WHERE (consumer_pk = :cid) AND (resource_link_pk = :id)'; $query = oci_parse($this->db, $sql); - oci_bind_by_name($query, 'ctx', $contextId); $rlid = $resourceLink->getId(); oci_bind_by_name($query, 'rlid', $rlid); oci_bind_by_name($query, 'settings', $settingsValue); oci_bind_by_name($query, 'prlid', $primaryResourceLinkId); - oci_bind_by_name($query, 'share_approved', $resourceLink->shareApproved); + oci_bind_by_name($query, 'share_approved', $approved); oci_bind_by_name($query, 'updated', $now); oci_bind_by_name($query, 'cid', $consumerId); oci_bind_by_name($query, 'id', $id); @@ -892,7 +903,9 @@ public function getSharesResourceLink($resourceLink) while ($row = oci_fetch_assoc($query)) { $row = array_change_key_case($row); $share = new LTI\ResourceLinkShare(); + $share->consumer_name = $row['consumer_name']; $share->resourceLinkId = intval($row['resource_link_pk']); + $share->title = $row['title']; $share->approved = (intval($row['share_approved']) === 1); $shares[] = $share; } @@ -994,11 +1007,10 @@ public function loadResourceLinkShareKey($shareKey) $row = oci_fetch_assoc($query); if ($row !== false) { $row = array_change_key_case($row); - if (intval($row['resource_link_pk']) === $shareKey->resourceLinkId) { - $shareKey->autoApprove = ($row['auto_approve'] === 1); - $shareKey->expires = strtotime($row['expires']); - $ok = true; - } + $shareKey->resourceLinkId = intval($row['resource_link_pk']); + $shareKey->autoApprove = (intval($row['auto_approve']) === 1); + $shareKey->expires = strtotime($row['expires']); + $ok = true; } } diff --git a/src/DataConnector/DataConnector_pdo.php b/src/DataConnector/DataConnector_pdo.php index cfbf18e..d3b1653 100644 --- a/src/DataConnector/DataConnector_pdo.php +++ b/src/DataConnector/DataConnector_pdo.php @@ -474,7 +474,7 @@ public function saveContext($context) $query->bindValue('updated', $now, \PDO::PARAM_STR); } else { $sql = "UPDATE {$this->dbTableNamePrefix}" . static::CONTEXT_TABLE_NAME . ' SET ' . - 'title = :title, lti_context_id = :ctx, type = :type, settings = :settings, ' . + 'title = :title, lti_context_id = :ctx, type = :type, settings = :settings, ' . 'updated = :updated ' . 'WHERE (consumer_pk = :cid) AND (context_pk = :ctxid)'; $query = $this->db->prepare($sql); @@ -568,12 +568,17 @@ public function loadResourceLink($resourceLink) $query = $this->db->prepare($sql); $query->bindValue('id', $resourceLink->getRecordId(), \PDO::PARAM_INT); } elseif (!is_null($resourceLink->getContext())) { - $sql = 'SELECT resource_link_pk, context_pk, consumer_pk, title, lti_resource_link_id, settings, primary_resource_link_pk, share_approved, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' ' . - 'WHERE (context_pk = :id) AND (lti_resource_link_id = :rlid)'; + $sql = 'SELECT r.resource_link_pk, r.context_pk, r.consumer_pk, r.title, r.lti_resource_link_id, r.settings, r.primary_resource_link_pk, r.share_approved, r.created, r.updated ' . + "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' r ' . + 'WHERE (r.lti_resource_link_id = :rlid) AND ((r.context_pk = :id1) OR (r.consumer_pk IN (' . + 'SELECT c.consumer_pk ' . + "FROM {$this->dbTableNamePrefix}" . static::CONTEXT_TABLE_NAME . ' c ' . + 'WHERE (c.context_pk = :id2)' . + ')))'; $query = $this->db->prepare($sql); - $query->bindValue('id', $resourceLink->getContext()->getRecordId(), \PDO::PARAM_INT); $query->bindValue('rlid', $resourceLink->getId(), \PDO::PARAM_STR); + $query->bindValue('id1', $resourceLink->getContext()->getRecordId(), \PDO::PARAM_INT); + $query->bindValue('id2', $resourceLink->getContext()->getRecordId(), \PDO::PARAM_INT); } else { $sql = 'SELECT r.resource_link_pk, r.context_pk, r.consumer_pk, r.title, r.lti_resource_link_id, r.settings, r.primary_resource_link_pk, r.share_approved, r.created, r.updated ' . "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' r LEFT OUTER JOIN ' . @@ -635,17 +640,24 @@ public function loadResourceLink($resourceLink) */ public function saveResourceLink($resourceLink) { + if (is_null($resourceLink->shareApproved)) { + $approved = null; + } elseif ($resourceLink->shareApproved) { + $approved = 1; + } else { + $approved = 0; + } $time = time(); $now = date("{$this->dateFormat} {$this->timeFormat}", $time); $settingsValue = json_encode($resourceLink->getSettings()); if (!is_null($resourceLink->getContext())) { $consumerId = null; - $contextId = strval($resourceLink->getContext()->getRecordId()); + $contextId = $resourceLink->getContext()->getRecordId(); } elseif (!is_null($resourceLink->getContextId())) { $consumerId = null; - $contextId = strval($resourceLink->getContextId()); + $contextId = $resourceLink->getContextId(); } else { - $consumerId = strval($resourceLink->getConsumer()->getRecordId()); + $consumerId = $resourceLink->getConsumer()->getRecordId(); $contextId = null; } if (empty($resourceLink->primaryResourceLinkId)) { @@ -665,7 +677,7 @@ public function saveResourceLink($resourceLink) $query->bindValue('rlid', $resourceLink->getId(), \PDO::PARAM_STR); $query->bindValue('settings', $settingsValue, \PDO::PARAM_STR); $query->bindValue('prlid', $primaryResourceLinkId, \PDO::PARAM_INT); - $query->bindValue('share_approved', $resourceLink->shareApproved, \PDO::PARAM_INT); + $query->bindValue('share_approved', $approved, \PDO::PARAM_INT); $query->bindValue('created', $now, \PDO::PARAM_STR); $query->bindValue('updated', $now, \PDO::PARAM_STR); } elseif (!is_null($contextId)) { @@ -679,21 +691,20 @@ public function saveResourceLink($resourceLink) $query->bindValue('rlid', $resourceLink->getId(), \PDO::PARAM_STR); $query->bindValue('settings', $settingsValue, \PDO::PARAM_STR); $query->bindValue('prlid', $primaryResourceLinkId, \PDO::PARAM_INT); - $query->bindValue('share_approved', $resourceLink->shareApproved, \PDO::PARAM_INT); + $query->bindValue('share_approved', $approved, \PDO::PARAM_INT); $query->bindValue('updated', $now, \PDO::PARAM_STR); $query->bindValue('id', $id, \PDO::PARAM_INT); } else { $sql = "UPDATE {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' SET ' . - 'context_pk = :ctx, title = :title, lti_resource_link_id = :rlid, settings = :settings, ' . + 'context_pk = NULL, title = :title, lti_resource_link_id = :rlid, settings = :settings, ' . 'primary_resource_link_pk = :prlid, share_approved = :share_approved, updated = :updated ' . 'WHERE (consumer_pk = :cid) AND (resource_link_pk = :id)'; $query = $this->db->prepare($sql); - $query->bindValue('ctx', $contextId, \PDO::PARAM_INT); $query->bindValue('title', $resourceLink->title, \PDO::PARAM_STR); $query->bindValue('rlid', $resourceLink->getId(), \PDO::PARAM_STR); $query->bindValue('settings', $settingsValue, \PDO::PARAM_STR); $query->bindValue('prlid', $primaryResourceLinkId, \PDO::PARAM_INT); - $query->bindValue('share_approved', $resourceLink->shareApproved, \PDO::PARAM_INT); + $query->bindValue('share_approved', $approved, \PDO::PARAM_INT); $query->bindValue('updated', $now, \PDO::PARAM_STR); $query->bindValue('cid', $consumerId, \PDO::PARAM_INT); $query->bindValue('id', $id, \PDO::PARAM_INT); @@ -849,7 +860,9 @@ public function getSharesResourceLink($resourceLink) while ($row = $query->fetch(\PDO::FETCH_ASSOC)) { $row = array_change_key_case($row); $share = new LTI\ResourceLinkShare(); + $share->consumerName = $row['consumer_name']; $share->resourceLinkId = intval($row['resource_link_pk']); + $share->title = $row['title']; $share->approved = (intval($row['share_approved']) === 1); $shares[] = $share; } @@ -951,11 +964,10 @@ public function loadResourceLinkShareKey($shareKey) $row = $query->fetch(\PDO::FETCH_ASSOC); if ($row !== false) { $row = array_change_key_case($row); - if (intval($row['resource_link_pk']) === $shareKey->resourceLinkId) { - $shareKey->autoApprove = ($row['auto_approve'] === 1); - $shareKey->expires = strtotime($row['expires']); - $ok = true; - } + $shareKey->resourceLinkId = intval($row['resource_link_pk']); + $shareKey->autoApprove = (intval($row['auto_approve']) === 1); + $shareKey->expires = strtotime($row['expires']); + $ok = true; } } @@ -971,6 +983,11 @@ public function loadResourceLinkShareKey($shareKey) */ public function saveResourceLinkShareKey($shareKey) { + if ($shareKey->autoApprove) { + $approve = 1; + } else { + $approve = 0; + } $id = $shareKey->getId(); $expires = date("{$this->dateFormat} {$this->timeFormat}", $shareKey->expires); $sql = "INSERT INTO {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_SHARE_KEY_TABLE_NAME . ' ' . @@ -979,7 +996,7 @@ public function saveResourceLinkShareKey($shareKey) $query = $this->db->prepare($sql); $query->bindValue('id', $id, \PDO::PARAM_STR); $query->bindValue('prlid', $shareKey->resourceLinkId, \PDO::PARAM_INT); - $query->bindValue('approve', $shareKey->autoApprove, \PDO::PARAM_INT); + $query->bindValue('approve', $approve, \PDO::PARAM_INT); $query->bindValue('expires', $expires, \PDO::PARAM_STR); $ok = $this->executeQuery($sql, $query); diff --git a/src/DataConnector/DataConnector_pg.php b/src/DataConnector/DataConnector_pg.php index 3b9f3b0..880112f 100644 --- a/src/DataConnector/DataConnector_pg.php +++ b/src/DataConnector/DataConnector_pg.php @@ -477,10 +477,13 @@ public function loadResourceLink($resourceLink) "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' ' . 'WHERE (resource_link_pk = %d)', $resourceLink->getRecordId()); } elseif (!is_null($resourceLink->getContext())) { - $sql = sprintf('SELECT resource_link_pk, context_pk, consumer_pk, title, lti_resource_link_id, settings, primary_resource_link_pk, share_approved, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' ' . - 'WHERE (context_pk = %d) AND (lti_resource_link_id = %s)', $resourceLink->getContext()->getRecordId(), - $this->escape($resourceLink->getId())); + $sql = sprintf('SELECT r.resource_link_pk, r.context_pk, r.consumer_pk, r.title, r.lti_resource_link_id, r.settings, r.primary_resource_link_pk, r.share_approved, r.created, r.updated ' . + "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' r ' . + 'WHERE (r.lti_resource_link_id = %s) AND ((r.context_pk = %d) OR (r.consumer_pk IN (' . + 'SELECT c.consumer_pk ' . + "FROM {$this->dbTableNamePrefix}" . static::CONTEXT_TABLE_NAME . ' c ' . + 'WHERE (c.context_pk = %d))))', $this->escape($resourceLink->getId()), $resourceLink->getContext()->getRecordId(), + $resourceLink->getContext()->getRecordId()); } else { $sql = sprintf('SELECT r.resource_link_pk, r.context_pk, r.consumer_pk, r.title, r.lti_resource_link_id, r.settings, r.primary_resource_link_pk, r.share_approved, r.created, r.updated ' . "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' r LEFT OUTER JOIN ' . @@ -579,9 +582,9 @@ public function saveResourceLink($resourceLink) $this->escape($now), $contextId, $id); } else { $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' SET ' . - 'context_pk = %s, title = %s, lti_resource_link_id = %s, settings = %s, ' . + 'context_pk = NULL, title = %s, lti_resource_link_id = %s, settings = %s, ' . 'primary_resource_link_pk = %s, share_approved = %s, updated = %s ' . - 'WHERE (consumer_pk = %s) AND (resource_link_pk = %d)', $contextId, $this->escape($resourceLink->title), + 'WHERE (consumer_pk = %s) AND (resource_link_pk = %d)', $this->escape($resourceLink->title), $this->escape($resourceLink->getId()), $this->escape($settingsValue), $primaryResourceLinkId, $approved, $this->escape($now), $consumerId, $id); } @@ -712,7 +715,9 @@ public function getSharesResourceLink($resourceLink) if ($rsShare) { while ($row = pg_fetch_object($rsShare)) { $share = new LTI\ResourceLinkShare(); + $share->consumerName = $row->consumer_name; $share->resourceLinkId = intval($row->resource_link_pk); + $share->title = $row->title; $share->approved = (intval($row->share_approved) === 1); $shares[] = $share; } @@ -799,7 +804,8 @@ public function loadResourceLinkShareKey($shareKey) $rsShareKey = $this->executeQuery($sql); if ($rsShareKey) { $row = pg_fetch_object($rsShareKey); - if ($row && (intval($row->resource_link_pk) === $shareKey->resourceLinkId)) { + if ($row) { + $shareKey->resourceLinkId = intval($row->resource_link_pk); $shareKey->autoApprove = (intval($row->auto_approve) === 1); $shareKey->expires = strtotime($row->expires); $ok = true; diff --git a/src/DataConnector/DataConnector_sqlsrv.php b/src/DataConnector/DataConnector_sqlsrv.php index e40b539..8202310 100644 --- a/src/DataConnector/DataConnector_sqlsrv.php +++ b/src/DataConnector/DataConnector_sqlsrv.php @@ -220,17 +220,19 @@ public function deleteToolConsumer($consumer) $this->executeQuery($sql); // Update any resource links for which this consumer is acting as a primary resource link - $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' prl ' . - "INNER JOIN {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' . + $sql = sprintf('UPDATE prl ' . 'SET prl.primary_resource_link_pk = NULL, prl.share_approved = NULL ' . + "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' prl ' . + "INNER JOIN {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' . 'WHERE rl.consumer_pk = %d', $consumer->getRecordId()); $ok = $this->executeQuery($sql); // Update any resource links for contexts in which this consumer is acting as a primary resource link - $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' prl ' . + $sql = sprintf('UPDATE prl ' . + 'SET prl.primary_resource_link_pk = NULL, prl.share_approved = NULL ' . + "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' prl ' . "INNER JOIN {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' . "INNER JOIN {$this->dbTableNamePrefix}" . static::CONTEXT_TABLE_NAME . ' c ON rl.context_pk = c.context_pk ' . - 'SET prl.primary_resource_link_pk = NULL, prl.share_approved = NULL ' . 'WHERE c.consumer_pk = %d', $consumer->getRecordId()); $ok = $this->executeQuery($sql); @@ -442,9 +444,10 @@ public function deleteContext($context) $this->executeQuery($sql); // Update any resource links for which this consumer is acting as a primary resource link - $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' prl ' . - "INNER JOIN {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' . + $sql = sprintf('UPDATE prl ' . 'SET prl.primary_resource_link_pk = null, prl.share_approved = null ' . + "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' prl ' . + "INNER JOIN {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' rl ON prl.primary_resource_link_pk = rl.resource_link_pk ' . 'WHERE rl.context_pk = %d', $context->getRecordId()); $ok = $this->executeQuery($sql); @@ -485,10 +488,13 @@ public function loadResourceLink($resourceLink) "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' ' . 'WHERE (resource_link_pk = %d)', $resourceLink->getRecordId()); } elseif (!is_null($resourceLink->getContext())) { - $sql = sprintf('SELECT resource_link_pk, context_pk, consumer_pk, title, lti_resource_link_id, settings, primary_resource_link_pk, share_approved, created, updated ' . - "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' ' . - 'WHERE (context_pk = %d) AND (lti_resource_link_id = %s)', $resourceLink->getContext()->getRecordId(), - $this->escape($resourceLink->getId())); + $sql = sprintf('SELECT r.resource_link_pk, r.context_pk, r.consumer_pk, r.title, r.lti_resource_link_id, r.settings, r.primary_resource_link_pk, r.share_approved, r.created, r.updated ' . + "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' r ' . + 'WHERE (r.lti_resource_link_id = %s) AND ((r.context_pk = %d) OR (r.consumer_pk IN (' . + 'SELECT c.consumer_pk ' . + "FROM {$this->dbTableNamePrefix}" . static::CONTEXT_TABLE_NAME . ' c ' . + 'WHERE (c.context_pk = %d))))', $this->escape($resourceLink->getId()), $resourceLink->getContext()->getRecordId(), + $resourceLink->getContext()->getRecordId()); } else { $sql = sprintf('SELECT r.resource_link_pk, r.context_pk, r.consumer_pk, r.title, r.lti_resource_link_id, r.settings, r.primary_resource_link_pk, r.share_approved, r.created, r.updated ' . "FROM {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' r LEFT OUTER JOIN ' . @@ -587,9 +593,9 @@ public function saveResourceLink($resourceLink) $this->escape($now), $contextId, $id); } else { $sql = sprintf("UPDATE {$this->dbTableNamePrefix}" . static::RESOURCE_LINK_TABLE_NAME . ' SET ' . - 'context_pk = %s, title = %s, lti_resource_link_id = %s, settings = %s, ' . + 'context_pk = NULL, title = %s, lti_resource_link_id = %s, settings = %s, ' . 'primary_resource_link_pk = %s, share_approved = %s, updated = %s ' . - 'WHERE (consumer_pk = %s) AND (resource_link_pk = %d)', $contextId, $this->escape($resourceLink->title), + 'WHERE (consumer_pk = %s) AND (resource_link_pk = %d)', $this->escape($resourceLink->title), $this->escape($resourceLink->getId()), $this->escape($settingsValue), $primaryResourceLinkId, $approved, $this->escape($now), $consumerId, $id); } @@ -720,7 +726,9 @@ public function getSharesResourceLink($resourceLink) if ($rsShare) { while ($row = sqlsrv_fetch_object($rsShare)) { $share = new LTI\ResourceLinkShare(); + $share->consumerName = $row->consumer_name; $share->resourceLinkId = intval($row->resource_link_pk); + $share->title = $row->title; $share->approved = (intval($row->share_approved) === 1); $shares[] = $share; } @@ -808,7 +816,8 @@ public function loadResourceLinkShareKey($shareKey) $rsShareKey = $this->executeQuery($sql); if ($rsShareKey) { $row = sqlsrv_fetch_object($rsShareKey); - if ($row && (intval($row->resource_link_pk) === $shareKey->resourceLinkId)) { + if ($row) { + $shareKey->resourceLinkId = intval($row->resource_link_pk); $shareKey->autoApprove = (intval($row->auto_approve) === 1); $shareKey->expires = date_timestamp_get($row->expires); $ok = true; diff --git a/src/ResourceLink.php b/src/ResourceLink.php index 4ccb181..23b4220 100644 --- a/src/ResourceLink.php +++ b/src/ResourceLink.php @@ -362,6 +362,17 @@ public function getContextId() return $this->contextId; } + /** + * Set context. + * + * @param Context $context Context for this resource link. + */ + public function setContext($context) + { + $this->context = $context; + $this->contextId = $context->getRecordId(); + } + /** * Set context ID. * @@ -369,8 +380,10 @@ public function getContextId() */ public function setContextId($contextId) { - $this->context = null; - $this->contextId = $contextId; + if ($this->contextId !== $contextId) { + $this->context = null; + $this->contextId = $contextId; + } } /** @@ -529,6 +542,7 @@ public function hasMembershipsService() if (!$has) { $has = self::hasApiHook(self::$MEMBERSHIPS_SERVICE_HOOK, $this->getConsumer()->getFamilyCode()); } + return $has; } @@ -928,6 +942,11 @@ public function getMemberships($withGroups = false) $fullname = (isset($members[$i]['person_name_full'])) ? $members[$i]['person_name_full'] : ''; $userresult->setNames($firstname, $lastname, $fullname); +// Set the sourcedId + if (isset($members[$i]['person_sourcedid'])) { + $userresult->sourcedId = $members[$i]['person_sourcedid']; + } + // Set the user email $email = (isset($members[$i]['person_contact_email_primary'])) ? $members[$i]['person_contact_email_primary'] : ''; $userresult->setEmail($email, $this->getConsumer()->defaultEmail); @@ -1070,8 +1089,7 @@ public static function fromConsumer($consumer, $ltiResourceLinkId, $tempId = nul public static function fromContext($context, $ltiResourceLinkId, $tempId = null) { $resourceLink = new ResourceLink(); - $resourceLink->setContextId($context->getRecordId()); - $resourceLink->context = $context; + $resourceLink->setContext($context); $resourceLink->dataConnector = $context->getDataConnector(); $resourceLink->ltiResourceLinkId = $ltiResourceLinkId; if (!empty($ltiResourceLinkId)) { @@ -1081,6 +1099,7 @@ public static function fromContext($context, $ltiResourceLinkId, $tempId = null) $resourceLink->load(); $resourceLink->ltiResourceLinkId = $ltiResourceLinkId; } + $resourceLink->setContext($context); // Ensure context remains set } return $resourceLink; diff --git a/src/ResourceLinkShareKey.php b/src/ResourceLinkShareKey.php index b842329..014648f 100644 --- a/src/ResourceLinkShareKey.php +++ b/src/ResourceLinkShareKey.php @@ -93,10 +93,11 @@ public function __construct($resourceLink, $id = null) { $this->initialize(); $this->dataConnector = $resourceLink->getDataConnector(); - $this->resourceLinkId = $resourceLink->getRecordId(); $this->id = $id; if (!empty($id)) { $this->load(); + } else { + $this->resourceLinkId = $resourceLink->getRecordId(); } } diff --git a/src/ToolProvider.php b/src/ToolProvider.php index 0fcd261..96a715c 100644 --- a/src/ToolProvider.php +++ b/src/ToolProvider.php @@ -85,7 +85,7 @@ class ToolProvider */ private static $LTI_CONTEXT_SETTING_NAMES = array('custom_context_setting_url', 'custom_lineitems_url', 'custom_results_url', - 'custom_context_memberships_url'); + 'custom_context_memberships_url', 'custom_context_memberships_v2_url'); /** * Names of LTI parameters to be retained in the resource link settings property. @@ -94,7 +94,7 @@ class ToolProvider 'ext_ims_lis_basic_outcome_url', 'ext_ims_lis_resultvalue_sourcedids', 'ext_ims_lis_memberships_id', 'ext_ims_lis_memberships_url', 'ext_ims_lti_tool_setting', 'ext_ims_lti_tool_setting_id', 'ext_ims_lti_tool_setting_url', - 'custom_link_setting_url', + 'custom_link_setting_url', 'custom_link_memberships_url', 'custom_lineitem_url', 'custom_result_url'); /** @@ -1106,10 +1106,12 @@ private function authenticate() if (isset($this->messageParameters['custom_content_item_id'])) { $contentItemId = $this->messageParameters['custom_content_item_id']; } - $this->resourceLink = ResourceLink::fromConsumer($this->consumer, - trim($this->messageParameters['resource_link_id']), $contentItemId); - if (!empty($this->context)) { - $this->resourceLink->setContextId($this->context->getRecordId()); + if (empty($this->context)) { + $this->resourceLink = ResourceLink::fromConsumer($this->consumer, + trim($this->messageParameters['resource_link_id']), $contentItemId); + } else { + $this->resourceLink = ResourceLink::fromContext($this->context, + trim($this->messageParameters['resource_link_id']), $contentItemId); } $title = ''; if (isset($this->messageParameters['resource_link_title'])) { @@ -1283,27 +1285,30 @@ private function authenticate() if ($doSaveConsumer) { $this->consumer->save(); } - if ($this->ok && isset($this->context)) { - $this->context->save(); - } - if ($this->ok && isset($this->resourceLink)) { + if ($this->ok) { -// Check if a share arrangement is in place for this resource link - $this->ok = $this->checkForShare(); + if (isset($this->context)) { + $this->context->save(); + } + if (isset($this->resourceLink)) { // Persist changes to resource link - $this->resourceLink->save(); + $this->resourceLink->save(); // Save the user instance - $this->userResult->setResourceLinkId($this->resourceLink->getRecordId()); - if (isset($this->messageParameters['lis_result_sourcedid'])) { - if ($this->userResult->ltiResultSourcedId !== $this->messageParameters['lis_result_sourcedid']) { - $this->userResult->ltiResultSourcedId = $this->messageParameters['lis_result_sourcedid']; + $this->userResult->setResourceLinkId($this->resourceLink->getRecordId()); + if (isset($this->messageParameters['lis_result_sourcedid'])) { + if ($this->userResult->ltiResultSourcedId !== $this->messageParameters['lis_result_sourcedid']) { + $this->userResult->ltiResultSourcedId = $this->messageParameters['lis_result_sourcedid']; + $this->userResult->save(); + } + } elseif (!empty($this->userResult->ltiResultSourcedId)) { + $this->userResult->ltiResultSourcedId = ''; $this->userResult->save(); } - } elseif (!empty($this->userResult->ltiResultSourcedId)) { - $this->userResult->ltiResultSourcedId = ''; - $this->userResult->save(); + +// Check if a share arrangement is in place for this resource link + $this->ok = $this->checkForShare(); } } } @@ -1332,19 +1337,16 @@ private function checkForShare() } else { // Check if this is a new share key $shareKey = new ResourceLinkShareKey($this->resourceLink, $this->messageParameters['custom_share_key']); - if (!is_null($shareKey->primaryConsumerKey) && !is_null($shareKey->primaryResourceLinkId)) { + if (!is_null($shareKey->resourceLinkId)) { // Update resource link with sharing primary resource link details - $key = $shareKey->primaryConsumerKey; - $id = $shareKey->primaryResourceLinkId; - $ok = ($key !== $this->consumer->getKey()) || ($id != $this->resourceLink->getId()); + $id = $shareKey->resourceLinkId; + $ok = ($id != $this->resourceLink->getRecordId()); if ($ok) { - $this->resourceLink->primaryConsumerKey = $key; $this->resourceLink->primaryResourceLinkId = $id; $this->resourceLink->shareApproved = $shareKey->autoApprove; $ok = $this->resourceLink->save(); if ($ok) { $doSaveResourceLink = false; - $this->userResult->getResourceLink()->primaryConsumerKey = $key; $this->userResult->getResourceLink()->primaryResourceLinkId = $id; $this->userResult->getResourceLink()->shareApproved = $shareKey->autoApprove; $this->userResult->getResourceLink()->updated = time(); @@ -1358,7 +1360,7 @@ private function checkForShare() } } if ($ok) { - $ok = !is_null($key); + $ok = !is_null($id); if (!$ok) { $this->reason = 'You have requested to share a resource link but none is available.'; } else { @@ -1379,12 +1381,8 @@ private function checkForShare() // Look up primary resource link if ($ok && !is_null($id)) { - $consumer = new ToolConsumer($key, $this->dataConnector); - $ok = !is_null($consumer->created); - if ($ok) { - $resourceLink = ResourceLink::fromConsumer($consumer, $id); - $ok = !is_null($resourceLink->created); - } + $resourceLink = ResourceLink::fromRecordId($id, $this->dataConnector); + $ok = !is_null($resourceLink->created); if ($ok) { if ($doSaveResourceLink) { $this->resourceLink->save();