Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

creator as non-classic data object #161

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
Draft
4 changes: 4 additions & 0 deletions controllers/ApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,10 @@ public function init($extra) {
}
$this->objectLibraryID = Zotero_Groups::getLibraryIDFromGroupID($this->objectGroupID);
}
// Temporarily record shardID in GLOBALS so we can access it in header.inc.php
if (isset($this->objectLibraryID)) {
define('Z_TEMP_SHARD_MIGRATED', in_array(Zotero_Shards::getByLibraryID($this->objectLibraryID), $GLOBALS['updatedShards']));
}

$apiVersion = !empty($_SERVER['HTTP_ZOTERO_API_VERSION'])
? (int) $_SERVER['HTTP_ZOTERO_API_VERSION']
Expand Down
24 changes: 14 additions & 10 deletions controllers/ItemsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -378,19 +378,23 @@ public function items() {
if (!$tagIDs) {
$this->e404("Tag not found");
}

foreach ($tagIDs as $tagID) {
$tag = new Zotero_Tag;
$tag->libraryID = $this->objectLibraryID;
$tag->id = $tagID;
// Use a real tag name, in case case differs
if (!$title) {
$title = "Items of Tag ‘" . $tag->name . "’";
if (Z_TEMP_SHARD_MIGRATED) {
$linkedItemKeys = Zotero_Tags::loadLinkedItemsKeys($this->objectLibraryID, $this->scopeObjectName);
$itemKeys = array_merge($itemKeys, $linkedItemKeys);
}
else {
foreach ($tagIDs as $tagID) {
$tag = new Zotero_Tag;
$tag->libraryID = $this->objectLibraryID;
$tag->id = $tagID;
// Use a real tag name, in case case differs
if (!$title) {
$title = "Items of Tag ‘" . $tag->name . "’";
}
$itemKeys = array_merge($itemKeys, $tag->getLinkedItems(true));
}
$itemKeys = array_merge($itemKeys, $tag->getLinkedItems(true));
}
$itemKeys = array_unique($itemKeys);

break;

default:
Expand Down
29 changes: 24 additions & 5 deletions controllers/TagsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,14 @@ public function tags() {
}
$title = "Tags of '" . $item->getDisplayTitle() . "'";
$tagIDs = $item->getTags(true);
if (Z_TEMP_SHARD_MIGRATED) {
$tags = $item->getTags(true);
$tagIDs = array_map(function($tag) {
return $tag->id;
}, $tags);
} else {
$tagIDs = $item->getTags(true);
}
break;

default:
Expand All @@ -187,11 +195,22 @@ public function tags() {
$tagNames = !empty($this->queryParams['tag'])
? explode(' || ', $this->queryParams['tag']): array();
Zotero_DB::beginTransaction();
foreach ($tagNames as $tagName) {
$tagIDs = Zotero_Tags::getIDs($this->objectLibraryID, $tagName);
foreach ($tagIDs as $tagID) {
$tag = Zotero_Tags::get($this->objectLibraryID, $tagID, true);
Zotero_Tags::delete($this->objectLibraryID, $tag->key, $this->objectUserID);
// Different delete behavior depending on if we are on migrated shard or not
// because after migration $tag->key does not exist
if (Z_TEMP_SHARD_MIGRATED) {
$tagIDs = [];
foreach ($tagNames as $tagName) {
$tagIDs = array_merge($tagIDs, Zotero_Tags::getIDs($this->objectLibraryID, $tagName));
}
Zotero_Tags::bulkDelete($this->objectLibraryID, null, $tagIDs);
}
else {
foreach ($tagNames as $tagName) {
$tagIDs = Zotero_Tags::getIDs($this->objectLibraryID, $tagName);
foreach ($tagIDs as $tagID) {
$tag = Zotero_Tags::get($this->objectLibraryID, $tagID, true);
Zotero_Tags::delete($this->objectLibraryID, $tag->key, $this->objectUserID);
}
}
}
Zotero_DB::commit();
Expand Down
21 changes: 18 additions & 3 deletions include/header.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,23 @@ function zotero_autoload($className) {
else {
$auth = false;
}

$path = Z_ENV_BASE_PATH . 'model/';
$updatedShards = $GLOBALS['updatedShards'];
$newFiles = [
"Item.inc.php",
"Items.inc.php", "Cite.inc.php",
"Library.inc.php",
"Creator.inc.php",
"Creators.inc.php",
"Tag.inc.php",
"Tags.inc.php",
"TagsController.php"
];
if (defined('Z_TEMP_SHARD_MIGRATED') && !Z_TEMP_SHARD_MIGRATED && in_array($fileName, $newFiles)) {
$path = Z_ENV_BASE_PATH . 'model/old_';
}
else {
$path = Z_ENV_BASE_PATH . 'model/';
}
if ($auth) {
$path .= 'auth/';
}
Expand Down Expand Up @@ -74,7 +89,7 @@ function zotero_autoload($className) {
return;
}
}

$GLOBALS['updatedShards'] = [1];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be empty in the committed code

spl_autoload_register('zotero_autoload');

// Read in configuration variables
Expand Down
71 changes: 71 additions & 0 deletions misc/db-updates/2023-07-17/creatorsAsNonClassicDataObjects
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/usr/local/bin/php -d mysqlnd.net_read_timeout=86400
<?php
set_include_path("../../../include");
require("header.inc.php");

$shardHostID = $argv[1];
$startShard = $argv[2];
$stopShard = $argv[3];

Z_Core::$debug = true;

$shardIDs = Zotero_DB::columnQuery("SELECT shardID FROM shards WHERE shardHostID=? AND shardID >= ? AND shardID <= ? ORDER BY shardID", [$shardHostID, $startShard, $stopShard]);
foreach ($shardIDs as $shardID) {
echo "Shard: $shardID\n";

echo "Setting shard to readonly\n";
Zotero_DB::query("UPDATE shards SET state='readonly' WHERE shardID=?", $shardID);

echo "Waiting 60 seconds for requests to stop\n";
sleep(60);

// Creators
echo "Migrating creators\n";
// Drop foreign key constraint
Zotero_Admin_DB::query("ALTER TABLE `itemCreators` DROP CONSTRAINT `itemCreators_ibfk_1`", false, $shardID);
Zotero_Admin_DB::query("ALTER TABLE `itemCreators` DROP CONSTRAINT `itemCreators_ibfk_2`", false, $shardID);

// Create new itemCreators table
Zotero_Admin_DB::query("CREATE TABLE `itemCreatorsNew` (`itemID` BIGINT UNSIGNED NOT NULL, `firstName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, `lastName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, `fieldMode` tinyint(1) UNSIGNED DEFAULT NULL, `creatorTypeID` smallint(5) UNSIGNED NOT NULL, `orderIndex` smallint(5) UNSIGNED NOT NULL, PRIMARY KEY (`itemID`, `orderIndex`)) ENGINE=InnoDB DEFAULT CHARSET=utf8", false, $shardID);

// Add foreign key to item constraint
Zotero_Admin_DB::query("ALTER TABLE `itemCreatorsNew` ADD CONSTRAINT `itemCreators_ibfk_1` FOREIGN KEY (`itemID`) REFERENCES `items` (`itemID`) ON DELETE CASCADE", false, $shardID);

// Populate new table with data
Zotero_Admin_DB::query("INSERT INTO itemCreatorsNew (firstName, lastName, fieldMode, itemID, creatorTypeID, orderIndex ) SELECT firstName, lastName, fieldMode, itemID, creatorTypeID, orderIndex from creators INNER JOIN itemCreators USING (creatorID)", false, $shardID);

// Drop old creators tables
Zotero_Admin_DB::query("DROP TABLE itemCreators", false, $shardID);
Zotero_Admin_DB::query("DROP TABLE creators", false, $shardID);

// Rename old itemCreators table
Zotero_Admin_DB::query("RENAME TABLE itemCreatorsNew TO itemCreators", false, $shardID);

// Tags
echo "Migrating tags\n";
// Drop foreign key constraint
Zotero_Admin_DB::query("ALTER TABLE `itemTags` DROP CONSTRAINT `itemTags_ibfk_1`", false, $shardID);
Zotero_Admin_DB::query("ALTER TABLE `itemTags` DROP CONSTRAINT `itemTags_ibfk_2`", false, $shardID);

// Create new itemTags table
Zotero_Admin_DB::query("CREATE TABLE `itemTagsNew` ( `tagID` BIGINT UNSIGNED NOT NULL, `itemID` BIGINT UNSIGNED NOT NULL, `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `type` tinyint(1) unsigned NOT NULL DEFAULT '0', `version` int(10) unsigned NOT NULL DEFAULT '1', PRIMARY KEY (`tagID`, `itemID`), KEY `nameType` (`name`, `type`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8", false, $shardID);

// Add foreign key to item constraint
Zotero_Admin_DB::query("ALTER TABLE `itemTagsNew` ADD CONSTRAINT `itemTags_ibfk_1` FOREIGN KEY (`itemID`) REFERENCES `items` (`itemID`) ON DELETE CASCADE", false, $shardID);

// Populate new table with data
Zotero_Admin_DB::query("INSERT INTO itemTagsNew (tagID, itemID, name, type, version) SELECT tagID, itemID, name, type, version from tags INNER JOIN itemTags USING (tagID)", false, $shardID);

// Drop old creators tables
Zotero_Admin_DB::query("DROP TABLE itemTags", false, $shardID);
Zotero_Admin_DB::query("DROP TABLE tags", false, $shardID);

// Rename old itemTags table
Zotero_Admin_DB::query("RENAME TABLE itemTagsNew TO itemTags", false, $shardID);


echo "Bringing shard back up\n";
Zotero_DB::query("UPDATE shards SET state='up' WHERE shardID=?", $shardID);
echo "Done with shard $shardID\n\n";
sleep(1);
}
2 changes: 1 addition & 1 deletion misc/shard.sql
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need all the schema changes here

Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ CREATE TABLE `syncDeleteLogIDs` (

CREATE TABLE `syncDeleteLogKeys` (
`libraryID` int(10) unsigned NOT NULL,
`objectType` enum('collection','creator','item','relation','search','setting','tag','tagName') NOT NULL,
`objectType` enum('collection','item','relation','search','setting','tag','tagName') NOT NULL,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tag should be removed

`key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`version` int(10) unsigned NOT NULL DEFAULT '1',
Expand Down
6 changes: 3 additions & 3 deletions model/Cite.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -297,17 +297,17 @@ public static function retrieveItem($zoteroItem) {
$authorID = Zotero_CreatorTypes::getPrimaryIDForType($zoteroItem->itemTypeID);
$creators = $zoteroItem->getCreators();
foreach ($creators as $creator) {
if ($creator['creatorTypeID'] == $authorID) {
if ($creator->creatorTypeID == $authorID) {
$creatorType = "author";
}
else {
$creatorType = Zotero_CreatorTypes::getName($creator['creatorTypeID']);
$creatorType = Zotero_CreatorTypes::getName($creator->creatorTypeID);
}

$creatorType = isset(self::$zoteroNameMap[$creatorType]) ? self::$zoteroNameMap[$creatorType] : false;
if (!$creatorType) continue;

$nameObj = array('family' => $creator['ref']->lastName, 'given' => $creator['ref']->firstName);
$nameObj = array('family' => $creator->lastName, 'given' => $creator->firstName);

if (isset($cslItem[$creatorType])) {
$cslItem[$creatorType][] = $nameObj;
Expand Down
10 changes: 3 additions & 7 deletions model/Collection.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,7 @@ public function getRelations() {
* Returns all tags assigned to items in this collection
*/
public function getTags($asIDs=false) {
$sql = "SELECT tagID FROM tags JOIN itemTags USING (tagID)
$sql = "SELECT tagID FROM itemTags
JOIN collectionItems USING (itemID) WHERE collectionID=? ORDER BY name";
$tagIDs = Zotero_DB::columnQuery($sql, $this->id, Zotero_Shards::getByLibraryID($this->libraryID));
if (!$tagIDs) {
Expand All @@ -604,11 +604,7 @@ public function getTags($asIDs=false) {
return $tagIDs;
}

$tagObjs = array();
foreach ($tagIDs as $tagID) {
$tag = Zotero_Tags::get($tagID, true);
$tagObjs[] = $tag;
}
$tagObjs = Zotero_Tags::bulkGet($this->libraryID, $tagIDs);
return $tagObjs;
}

Expand All @@ -618,7 +614,7 @@ public function getTags($asIDs=false) {
* in this collection
*/
public function getTagItemCounts() {
$sql = "SELECT tagID, COUNT(*) AS numItems FROM tags JOIN itemTags USING (tagID)
$sql = "SELECT tagID, COUNT(*) AS numItems FROM itemTags
JOIN collectionItems USING (itemID) WHERE collectionID=? GROUP BY tagID";
$rows = Zotero_DB::query($sql, $this->id, Zotero_Shards::getByLibraryID($this->libraryID));
if (!$rows) {
Expand Down
Loading