From 4b87c22904440f8bd490271dc4c05d029e4f1008 Mon Sep 17 00:00:00 2001 From: coderkun Date: Sat, 21 Mar 2015 15:15:49 +0100 Subject: [PATCH] implement copying a complete Seminary (implements issue #7) --- app/exceptions/FileCopyException.inc | 79 ++++++ app/models/QuesttypeModel.inc | 13 +- configs/AppConfig.inc | 4 +- controllers/SeminariesController.inc | 156 +++++++++++- locale/de_DE/LC_MESSAGES/The Legend of Z.mo | Bin 24621 -> 25124 bytes locale/de_DE/LC_MESSAGES/The Legend of Z.po | 240 ++++++++++++------ models/AchievementsModel.inc | 236 ++++++++++++++++- models/AvatarsModel.inc | 77 ++++++ models/CharactergroupsModel.inc | 36 +++ models/CharactergroupsquestsModel.inc | 53 +++- models/CharactertypesModel.inc | 36 +++ models/MediaModel.inc | 161 +++++++++++- models/QuestgroupsModel.inc | 133 +++++++++- models/QuestgroupshierarchyModel.inc | 76 +++++- models/QuestgrouptextsModel.inc | 74 ++---- models/QuestsModel.inc | 85 ++++++- models/QuesttextsModel.inc | 57 +++++ models/QuesttopicsModel.inc | 75 ++++++ models/SeminariesModel.inc | 142 ++++++++++- models/SeminarycharacterfieldsModel.inc | 22 ++ models/XplevelsModel.inc | 36 +++ .../bossfight/BossfightQuesttypeModel.inc | 98 ++++++- .../choiceinput/ChoiceinputQuesttypeModel.inc | 73 ++++++ .../crossword/CrosswordQuesttypeModel.inc | 24 ++ .../dragndrop/DragndropQuesttypeModel.inc | 105 ++++++++ .../MultiplechoiceQuesttypeModel.inc | 44 ++++ questtypes/submit/SubmitQuesttypeModel.inc | 13 + .../textinput/TextinputQuesttypeModel.inc | 36 +++ views/html/seminaries/copy.tpl | 116 +++++++++ views/html/seminaries/seminary.tpl | 1 + www/css/desktop.css | 7 + 31 files changed, 2151 insertions(+), 157 deletions(-) create mode 100644 app/exceptions/FileCopyException.inc create mode 100644 views/html/seminaries/copy.tpl diff --git a/app/exceptions/FileCopyException.inc b/app/exceptions/FileCopyException.inc new file mode 100644 index 00000000..898cb7b1 --- /dev/null +++ b/app/exceptions/FileCopyException.inc @@ -0,0 +1,79 @@ + + * @copyright 2014 Heinrich-Heine-Universität Düsseldorf + * @license http://www.gnu.org/licenses/gpl.html + * @link https://bitbucket.org/coderkun/the-legend-of-z + */ + + namespace hhu\z\exceptions; + + + /** + * Exception: File copy went wrong + * + * @author Oliver Hanraths + */ + class FileCopyException extends \nre\core\Exception + { + /** + * Error code + * + * @var int + */ + const CODE = 204; + /** + * Error message + * + * @var string + */ + const MESSAGE = 'File copy went wrong'; + + /** + * Nested error + * + * @var array + */ + private $nestedError; + + + + + /** + * Construct a new exception. + * + * @param array $nestedError Nested error + * @param string $message Error message + * @param int $code Error code + */ + function __construct($nestedError, $message=self::MESSAGE, $code=self::CODE) + { + parent::__construct( + $message, + $code, + $nestedError['message'] + ); + + // Store values + $this->nestedError = $nestedError; + } + + + + + /** + * Get nested error. + * + * @return Nested error + */ + public function getNestedError() + { + return $this->nestedError; + } + + } + +?> diff --git a/app/models/QuesttypeModel.inc b/app/models/QuesttypeModel.inc index 545b24eb..fdeafe81 100644 --- a/app/models/QuesttypeModel.inc +++ b/app/models/QuesttypeModel.inc @@ -22,7 +22,18 @@ - + + /** + * Copy a Quest. + * + * @param int $userId ID of creating user + * @param int $sourceQuestId ID of Quest to copy from + * @param int $targetQuestId ID of Quest to copy to + * @param int $seminaryMediaIds Mapping of SeminaryMedia-IDs from source Seminary to targetSeminary + */ + public abstract function copyQuest($userId, $sourceQuestId, $targetQuestId, $seminaryMediaIds); + + /** * Load a Model. * diff --git a/configs/AppConfig.inc b/configs/AppConfig.inc index 6520b377..aa637e03 100644 --- a/configs/AppConfig.inc +++ b/configs/AppConfig.inc @@ -244,8 +244,8 @@ array('^users/all/?$', 'users/index/all', true), array('^users/([^/]+)/(edit|delete)/?$', 'users/$2/$1', true), array('^users/(?!(index|login|register|logout|manage|create|edit|delete))/?', 'users/user/$1', true), - array('^seminaries/([^/]+)/(edit|delete)/?$', 'seminaries/$2/$1', true), - array('^seminaries/(?!(index|create|edit|delete|calculatexps))/?', 'seminaries/seminary/$1', true), + array('^seminaries/([^/]+)/(edit|copy|delete)/?$', 'seminaries/$2/$1', true), + array('^seminaries/(?!(index|create|edit|copy|delete|calculatexps))/?', 'seminaries/seminary/$1', true), array('^xplevels/([^/]+)/(manage)/?$', 'xplevels/$2/$1', true), array('^questgroupshierarchy/([^/]+)/create/?$', 'questgroupshierarchy/create/$1', true), array('^questgroupshierarchy/([^/]+)/([^/]+)/(edit|delete|moveup|movedown)/?$', 'questgroupshierarchy/$3/$1/$2', true), diff --git a/controllers/SeminariesController.inc b/controllers/SeminariesController.inc index 89ce5fa0..3be361a5 100644 --- a/controllers/SeminariesController.inc +++ b/controllers/SeminariesController.inc @@ -24,7 +24,7 @@ * * @var array */ - public $models = array('seminaries', 'users', 'characterroles', 'charactertypes', 'xplevels', 'questgroupshierarchy', 'questgroups', 'questgrouptexts', 'media'); + public $models = array('users', 'seminaries', 'characterroles', 'charactertypes', 'xplevels', 'questgroupshierarchy', 'questgroups', 'questgrouptexts', 'quests', 'questtexts', 'media'); /** * Required components * @@ -41,6 +41,7 @@ 'seminary' => array('admin', 'moderator', 'user'), 'create' => array('admin', 'moderator'), 'edit' => array('admin', 'moderator', 'user'), + 'copy' => array('admin', 'moderator', 'user'), 'delete' => array('admin', 'moderator', 'user'), 'calculatexps' => array('admin', 'moderator', 'user') ); @@ -52,6 +53,7 @@ public $seminaryPermissions = array( 'seminary' => array('admin', 'moderator', 'user', 'guest'), 'edit' => array('admin'), + 'copy' => array('admin'), 'delete' => array('admin'), 'calculatexps' => array('admin', 'moderator') ); @@ -138,7 +140,7 @@ } // Get first Questgroup text - $text = $this->Questgrouptexts->getFirstQuestgroupText($questgroup['id']); + $text = $this->getFirstQuestgroupText($questgroup['id']); if(!is_null($text)) { $questgroup['text'] = \hhu\z\Utils::shortenString($text, 100, 120).' …'; @@ -390,6 +392,101 @@ $this->set('validation', $validation); $this->set('validationSettings', $validationSettings); } + + + /** + * Copy a Seminary and selected content. + * + * @throws \nre\exceptions\IdNotFoundException + * @param string $seminaryUrl URL-Title of a seminary + */ + public function copy($seminaryUrl) + { + // Get seminary + $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl); + + // Values + $title = sprintf('%s (%s)', $seminary['title'], _('Copy')); + $course = $seminary['course']; + $description = $seminary['description']; + $elements = array(); + $fields = array('title', 'course'); + $validation = array(); + $exception = null; + + // Check request method + if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('edit'))) + { + // Get params and validate them + $validation = $this->Validation->validateParams($this->request->getPostParams(), $fields); + $title = $this->request->getPostParam('title'); + if($this->Seminaries->seminaryTitleExists($title)) { + $validation = $this->Validation->addValidationResult($validation, 'title', 'exist', true); + } + $course = $this->request->getPostParam('course'); + $description = $this->request->getPostParam('description'); + $elements = $this->request->getPostParam('elements'); + if(!is_array($elements)) { + $elements = array(); + } + + // Copy Seminary + if($validation === true) + { + try { + $seminaryId = $this->Seminaries->copySeminary( + $this->Auth->getUserId(), + $seminary['id'], + $title, + $course, + $description, + array_key_exists('seminaryfields', $elements), + array_key_exists('media', $elements), + array_key_exists('questgroupshierarchy', $elements), + array_key_exists('questgroups', $elements), + array_key_exists('quests', $elements), + array_key_exists('questtopics', $elements), + array_key_exists('charactertypes', $elements), + array_key_exists('xplevels', $elements), + array_key_exists('avatars', $elements), + array_key_exists('achievements', $elements), + array_key_exists('charactergroupsgroups', $elements), + array_key_exists('charactergroupsquests', $elements) + ); + $seminary = $this->Seminaries->getSeminaryById($seminaryId); + + // Redirect to overview + $this->redirect($this->linker->link('index', 1)); + } + catch(\hhu\z\exceptions\QuesttypeModelNotValidException $e) { + $exception = $e; + } + catch(\hhu\z\exceptions\QuesttypeModelNotFoundException $e) { + $exception = $e; + } + catch(\hhu\z\exceptions\FileCopyException $e) { + $exception = $e; + } + } + } + + // Get validation settings + $validationSettings = array(); + foreach($fields as &$field) { + $validationSettings[$field] = \nre\configs\AppConfig::$validation[$field]; + } + + + // Pass data to view + $this->set('seminary', $seminary); + $this->set('title', $title); + $this->set('course', $course); + $this->set('description', $description); + $this->set('elements', $elements); + $this->set('validation', $validation); + $this->set('validationSettings', $validationSettings); + $this->set('exception', $exception); + } /** @@ -444,22 +541,59 @@ // Get Seminary $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl); - // Questgrouphierarchy and Questgroups - $questgroupshierarchy = $this->Questgroupshierarchy->getHierarchyOfSeminary($seminary['id']); - foreach($questgroupshierarchy as &$hierarchy) + // (Re-) Calculate XPs + $this->Seminaries->calculateXPsForSeminary($seminary['id']); + + // Redirect to Questgroup + $this->redirect($this->linker->link(array('seminary', $seminary['url']), 1)); + } + + + + + /** + * Get the first text of a Questgroup. + * + * @param int $questgroupId ID of a Questgroup + * @return string First text of this Questgroup or NULL + */ + private function getFirstQuestgroupText($questgroupId) + { + // Text of Questgroup itself + $questgroupTexts = $this->Questgrouptexts->getQuestgroupTexts($questgroupId); + if(!empty($questgroupTexts)) { + return $questgroupTexts[0]['text']; + } + + // Text of first Quest + $quest = $this->Quests->getFirstQuestOfQuestgroup($questgroupId); + if(!is_null($quest)) + { + $questText = $this->Questtexts->getFirstQuestText($quest['id']); + if(!is_null($questText)) { + return $questText; + } + } + + // Text of ChildQuestgroups + $questgroupHierarchy = $this->Questgroupshierarchy->getHierarchyForQuestgroup($questgroupId); + $childQuestgroupshierarchy = $this->Questgroupshierarchy->getChildQuestgroupshierarchy($questgroupHierarchy['id']); + foreach($childQuestgroupshierarchy as &$hierarchy) { // Get Questgroups - $hierarchy['questgroups'] = $this->Questgroups->getQuestgroupsForHierarchy($hierarchy['id']); - foreach($hierarchy['questgroups'] as &$questgroup) + $questgroups = $this->Questgroups->getQuestgroupsForHierarchy($hierarchy['id'], $questgroupId); + foreach($questgroups as &$group) { - // Calculate achievable XPs - $this->Questgroups->calculateXPsForQuestgroup($questgroup['id']); + $childQuestgroupText = $this->getFirstQuestgroupText($group['id']); + if(!is_null($childQuestgroupText)) { + return $childQuestgroupText; + } } } - // Redirect to Questgroup - $this->redirect($this->linker->link(array('seminary', $seminary['url']), 1)); + // No text found + return null; } } diff --git a/locale/de_DE/LC_MESSAGES/The Legend of Z.mo b/locale/de_DE/LC_MESSAGES/The Legend of Z.mo index f80a3f79d6dd3b8a260c902f049fc01a346e4fe3..2376872547aa449f41eb5488fbb41b1f015faa45 100644 GIT binary patch delta 8519 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 delta 8019 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 TJC=*^4j4S$&wFl2zTf`db->query( - 'SELECT id, created, created_user_id, achievementcondition_id, pos, title, url, description, progress, hidden, only_once, all_conditions, deadline, unachieved_achievementsmedia_id, achieved_achievementsmedia_id '. + 'SELECT achievements.id, achievementconditions.condition, seminary_id, pos, title, url, description, progress, hidden, only_once, all_conditions, deadline, unachieved_achievementsmedia_id, achieved_achievementsmedia_id '. 'FROM achievements '. + 'LEFT JOIN achievementconditions ON achievementconditions.id = achievements.achievementcondition_id '. 'WHERE seminary_id = ? '. 'ORDER BY pos ASC', 'i', @@ -371,6 +378,28 @@ } + /** + * Copy all date conditions of an Achievement. + * + * @param int $userId ID of creating user + * @param int $sourceAchievementId ID of Achievement to copy conditions from + * @param int $targetAchievementId ID of Achievement to copy conditions to + */ + public function copyAchievementConditionsDate($userId, $sourceAchievementId, $targetAchievementId) + { + $this->db->query( + 'INSERT INTO achievementconditions_date '. + '(created_user_id, achievement_id, `select`) '. + 'SELECT ?, ?, `select` '. + 'FROM achievementconditions_date '. + 'WHERE achievement_id = ?', + 'iii', + $userId, $targetAchievementId, + $sourceAchievementId + ); + } + + /** * Delete a date condition. * @@ -519,6 +548,28 @@ } + /** + * Copy all Character conditions of an Achievement. + * + * @param int $userId ID of creating user + * @param int $sourceAchievementId ID of Achievement to copy conditions from + * @param int $targetAchievementId ID of Achievement to copy conditions to + */ + public function copyAchievementConditionsCharacter($userId, $sourceAchievementId, $targetAchievementId) + { + $this->db->query( + 'INSERT INTO achievementconditions_character '. + '(created_user_id, achievement_id, field, value) '. + 'SELECT ?, ?, field, value '. + 'FROM achievementconditions_character '. + 'WHERE achievement_id = ?', + 'iii', + $userId, $targetAchievementId, + $sourceAchievementId + ); + } + + /** * Delete a Character condition. * @@ -696,6 +747,52 @@ } + /** + * Copy all Quest conditions of an Achievement. + * + * @param int $userId ID of creating user + * @param int $sourceAchievementId ID of Achievement to copy conditions from + * @param int $targetAchievementId ID of Achievement to copy conditions to + * @param array $questIds Mapping of Quest-IDs from source Seminary to target Seminary + */ + public function copyAchievementConditionsQuest($userId, $sourceAchievementId, $targetAchievementId, $questIds) + { + // Get conditions + $conditions = $this->getAchievementConditionsQuest($sourceAchievementId); + + // Copy each condition + foreach($conditions as &$condition) + { + if(is_null($condition['quest_id'])) + { + $this->db->query( + 'INSERT INTO achievementconditions_quest '. + '(created_user_id, achievement_id, field, count, value, status, groupby) '. + 'SELECT ?, ?, field, count, value, status, groupby '. + 'FROM achievementconditions_quest '. + 'WHERE id = ?', + 'iii', + $userId, $targetAchievementId, + $condition['id'] + ); + } + else + { + $this->db->query( + 'INSERT INTO achievementconditions_quest '. + '(created_user_id, achievement_id, field, count, value, quest_id, status, groupby) '. + 'SELECT ?, ?, field, count, value, ?, status, groupby '. + 'FROM achievementconditions_quest '. + 'WHERE id = ?', + 'iiii', + $userId, $targetAchievementId, $questIds[$condition['quest_id']], + $condition['id'] + ); + } + } + } + + /** * Delete a Quest condition. * @@ -865,6 +962,52 @@ } + /** + * Copy all Achievement conditions of an Achievement. + * + * @param int $userId ID of creating user + * @param int $sourceAchievementId ID of Achievement to copy conditions from + * @param int $targetAchievementId ID of Achievement to copy conditions to + * @param array $achievementIds Mapping of Achievement-IDs from source Seminary to target Seminary + */ + public function copyAchievementConditionsAchievement($userId, $sourceAchievementId, $targetAchievementId, $achievementIds) + { + // Get conditions + $conditions = $this->getAchievementConditionsAchievement($sourceAchievementId); + + // Copy each condition + foreach($conditions as &$condition) + { + if(is_null($condition['meta_achievement_id']) || !array_key_exists($condition['meta_achievement_id'], $achievementIds)) + { + $this->db->query( + 'INSERT INTO achievementconditions_achievement '. + '(created_user_id, achievement_id, field, count, value, groupby) '. + 'SELECT ?, ?, field, count, value, groupby '. + 'FROM achievementconditions_achievement '. + 'WHERE id = ?', + 'iii', + $userId, $targetAchievementId, + $condition['id'] + ); + } + else + { + $this->db->query( + 'INSERT INTO achievementconditions_achievement '. + '(created_user_id, achievement_id, field, count, value, meta_achievement_id, groupby) '. + 'SELECT ?, ?, field, count, value, ?, groupby '. + 'FROM achievementconditions_achievement '. + 'WHERE id = ?', + 'iiii', + $userId, $targetAchievementId, $achievementIds[$condition['meta_achievement_id']], + $condition['id'] + ); + } + } + } + + /** * Delete a Achievement condition. * @@ -1134,6 +1277,97 @@ ); } + + /** + * Copy all Achievements of a Seminary. + * + * @param int $userId ID of creating user + * @param int $sourceSeminaryId Seminary to copy from + * @param int $targetSeminaryId Seminary to copy to + * @param array $seminaryMediaIds Mapping of Seminarymedia-IDs from source Seminary to target Seminary + * @param array $questIds Mapping of Quest-IDs from source Seminary to target Seminary (optional) + */ + public function copyAchievementsOfSeminary($userId, $sourceSeminaryId, $targetSeminaryId, $seminaryMediaIds, $questIds=null) + { + $achievementIds = array(); + + // Get Achievements + $achievements = $this->getAchievementsForSeminary($sourceSeminaryId); + + // Copy each Achievements + foreach($achievements as &$achievement) + { + // Check Quest-IDs + if($achievement['condition'] == 'quest' && is_null($questIds)) { + continue; + } + + // Copy Achievement + $this->db->query( + 'INSERT INTO achievements '. + '(created_user_id, seminary_id, achievementcondition_id, pos, title, url, description, progress, hidden, only_once, all_conditions, deadline) '. + 'SELECT ?, ?, achievementcondition_id, pos, title, url, description, progress, hidden, only_once, all_conditions, deadline '. + 'FROM achievements '. + 'WHERE id = ?', + 'iii', + $userId, $targetSeminaryId, + $achievement['id'] + ); + $achievementIds[$achievement['id']] = $this->db->getInsertId(); + + // Copy media + if(!is_null($achievement['unachieved_achievementsmedia_id'])) + { + $this->Media->copyAchievementMedia($userId, $seminaryMediaIds[$achievement['unachieved_achievementsmedia_id']]); + $this->db->query( + 'UPDATE achievements '. + 'SET unachieved_achievementsmedia_id = ? '. + 'WHERE id = ?', + 'ii', + $seminaryMediaIds[$achievement['unachieved_achievementsmedia_id']], + $achievementIds[$achievement['id']] + ); + } + if(!is_null($achievement['achieved_achievementsmedia_id'])) + { + $this->Media->copyAchievementMedia($userId, $seminaryMediaIds[$achievement['achieved_achievementsmedia_id']]); + $this->db->query( + 'UPDATE achievements '. + 'SET achieved_achievementsmedia_id = ? '. + 'WHERE id = ?', + 'ii', + $seminaryMediaIds[$achievement['achieved_achievementsmedia_id']], + $achievementIds[$achievement['id']] + ); + } + } + + // Copy Achievement conditions + // Do this after copying the Achievements itself to ensure Meta- + // Achievements work correctly + foreach($achievements as &$achievement) + { + // Copy conditions + switch($achievement['condition']) + { + case 'date': + $this->copyAchievementConditionsDate($userId, $achievement['id'], $achievementIds[$achievement['id']]); + break; + case 'quest': + if(!is_null($questIds)) { + $this->copyAchievementConditionsQuest($userId, $achievement['id'], $achievementIds[$achievement['id']], $questIds); + } + break; + case 'character': + $this->copyAchievementConditionsCharacter($userId, $achievement['id'], $achievementIds[$achievement['id']]); + break; + case 'achievement': + $this->copyAchievementConditionsAchievement($userId, $achievement['id'], $achievementIds[$achievement['id']], $achievementIds); + break; + } + } + } + /** * Delete an Achievement. diff --git a/models/AvatarsModel.inc b/models/AvatarsModel.inc index ad6af355..6bcf757f 100644 --- a/models/AvatarsModel.inc +++ b/models/AvatarsModel.inc @@ -19,6 +19,12 @@ */ class AvatarsModel extends \hhu\z\Model { + /** + * Required models + * + * @var array + */ + public $models = array('media'); @@ -88,6 +94,32 @@ } + /** + * Get an Avatar by its Character type and XP-level. + * + * @param int $charactertypeId ID of Character type + * @param int $xplevelId ID of XP-level + * @return array Avatar data + */ + public function getAvatarByTypeAndLevelId($charactertypeId, $xplevelId) + { + $data = $this->db->query( + 'SELECT id, charactertype_id, xplevel_id, avatarpicture_id, small_avatarpicture_id '. + 'FROM avatars '. + 'WHERE charactertype_id = ? AND xplevel_id = ?', + 'ii', + $charactertypeId, + $xplevelId + ); + if(empty($data)) { + throw new \nre\exceptions\IdNotFoundException($charactertypeId.'-'.$xplevelId); + } + + + return $data[0]; + } + + /** * Set the picture for an Avatar. * @@ -140,6 +172,51 @@ $avatarpictureId ); } + + + /** + * Copy all Avatars from a Seminary. + * + * @param int $userId ID of copying user + * @param array $charactertypeIds Mapping of Charactertype-IDs from source Seminary to target Seminary + * @param array $xplevelIds Mapping of XP-level-IDs from source Seminary to targetSeminary + * @param array $seminaryMediaIds Mapping of Seminarymedia-IDs from source Seminary to target Seminary + */ + public function copyAvatars($userId, $charactertypeIds, $xplevelIds, $seminaryMediaIds) + { + // Copy Avatars + foreach($charactertypeIds as $sourceCharactertypeId => $targetCharactertypeId) + { + foreach($xplevelIds as $sourceXplevelId => $targetXplevelId) + { + try { + // Get Avatar + $avatar = $this->getAvatarByTypeAndLevelId($sourceCharactertypeId, $sourceXplevelId); + + // Copy media + $this->Media->copyAvatarpicture($userId, $seminaryMediaIds[$avatar['avatarpicture_id']]); + $this->Media->copyAvatarpicture($userId, $seminaryMediaIds[$avatar['small_avatarpicture_id']]); + + // Copy Avatar + $this->db->query( + 'INSERT INTO avatars '. + '(created_user_id, charactertype_id, xplevel_id, avatarpicture_id, small_avatarpicture_id) '. + 'VALUES '. + '(?, ?, ?, ?, ?)', + 'iiiii', + $userId, + $targetCharactertypeId, + $targetXplevelId, + $seminaryMediaIds[$avatar['avatarpicture_id']], + $seminaryMediaIds[$avatar['small_avatarpicture_id']] + ); + } + catch(\nre\exceptions\IdNotFoundException $e) { + // Not all combinations of charactertypes and XP-levels exist + } + } + } + } } diff --git a/models/CharactergroupsModel.inc b/models/CharactergroupsModel.inc index 9accce7b..73978c04 100644 --- a/models/CharactergroupsModel.inc +++ b/models/CharactergroupsModel.inc @@ -176,6 +176,42 @@ $groupsgroupId ); } + + + /** + * Copy all Character groups-groups of a Seminary. + * + * @param int $userId ID of creating user + * @param int $sourceSeminaryId ID of Seminary to copy from + * @param int $targetSeminaryId ID of Seminary to copy to + * @param array Mapping of Character groups-groups-IDs from source Seminary to target Seminary + */ + public function copyGroupsgroupsOfSeminary($userId, $sourceSeminaryId, $targetSeminaryId) + { + $groupsgroupIds = array(); + + // Get Character groups + $groupsgroups = $this->getGroupsroupsForSeminary($sourceSeminaryId); + + // Copy each Groups-group + foreach($groupsgroups as &$group) + { + $this->db->query( + 'INSERT INTO charactergroupsgroups '. + '(created_user_id, seminary_id, name, url, preferred) '. + 'SELECT ?, ?, name, url, preferred '. + 'FROM charactergroupsgroups '. + 'WHERE id = ?', + 'iii', + $userId, $targetSeminaryId, + $group['id'] + ); + $groupsgroupIds[$group['id']] = $this->db->getInsertId(); + } + + + return $groupsgroupIds; + } /** diff --git a/models/CharactergroupsquestsModel.inc b/models/CharactergroupsquestsModel.inc index 1e55585b..52b7382b 100644 --- a/models/CharactergroupsquestsModel.inc +++ b/models/CharactergroupsquestsModel.inc @@ -25,7 +25,7 @@ * * @var array */ - public $models = array('uploads'); + public $models = array('uploads', 'media'); @@ -50,7 +50,7 @@ public function getQuestsForCharactergroupsgroup($groupsgroupId) { return $this->db->query( - 'SELECT id, questgroups_id, title, url, xps '. + 'SELECT id, questgroups_id, title, url, xps, questsmedia_id '. 'FROM charactergroupsquests '. 'WHERE charactergroupsgroup_id = ? '. 'ORDER BY created ASC', @@ -375,6 +375,55 @@ } + /** + * Copy all Character groups Quests from a Seminary. + * + * @param int $userId ID of copying user + * @param array $groupsgroupIds Mapping of Character groups-group-IDs from source Seminary to target Seminary + * @param array $questgroupIds Mapping of Questgroup-IDs from source Seminary to target Seminary + * @param array $seminaryMediaIds Mapping of Seminarymedia-IDs from source Seminary to target Seminary (optional) + */ + public function copyQuestsOfSeminary($userId, $groupsgroupIds, $questgroupIds, $seminaryMediaIds=null) + { + foreach($groupsgroupIds as $sourceGroupsgroupId => $targetGroupsgroupId) + { + // Get Quests + $quests = $this->getQuestsForCharactergroupsgroup($sourceGroupsgroupId); + + // Copy each Quest + foreach($quests as &$quest) + { + // Copy Quest + $this->db->query( + 'INSERT INTO charactergroupsquests '. + '(created_user_id, charactergroupsgroup_id, questgroups_id, title, url, description, xps, rules, won_text, lost_text) '. + 'SELECT ?, ?, ?, title, url, description, xps, rules, won_text, lost_text '. + 'FROM charactergroupsquests '. + 'WHERE id = ?', + 'iiii', + $userId, $targetGroupsgroupId, $questgroupIds[$quest['questgroups_id']], + $quest['id'] + ); + $targetQuestId = $this->db->getInsertId(); + + // Copy media + if(!is_null($seminaryMediaIds) && !is_null($quest['questsmedia_id'])) + { + $this->Media->copyQuestsmedia($userId, $seminaryMediaIds[$quest['questsmedia_id']]); + $this->db->query( + 'UPDATE charactergroupsquests '. + 'SET questsmedia_id = ? '. + 'WHERE id = ?', + 'ii', + $seminaryMediaIds[$quest['questsmedia_id']], + $targetQuestId + ); + } + } + } + } + + /** * Delete a Character groups Quest. * diff --git a/models/CharactertypesModel.inc b/models/CharactertypesModel.inc index eaa69e58..38a207eb 100644 --- a/models/CharactertypesModel.inc +++ b/models/CharactertypesModel.inc @@ -201,6 +201,42 @@ } + /** + * Copy all Charactertypes of a Seminary. + * + * @param int $userId ID of copying user + * @param int $sourceSeminaryId ID of Seminary to copy from + * @param int $targetSeminaryId ID of Seminary to copy to + * @param array Mapping of Charactertype-IDs from source Seminary to targetSeminary + */ + public function copyCharactertypesOfSeminary($userId, $sourceSeminaryId, $targetSeminaryId) + { + $charactertypeIds = array(); + + // Get Charactertypes + $charactertypes = $this->getCharacterTypesForSeminary($sourceSeminaryId); + + // Copy each Charactertype + foreach($charactertypes as &$type) + { + $this->db->query( + 'INSERT INTO charactertypes '. + '(created_user_id, seminary_id, name, url) '. + 'SELECT ?, ?, name, url '. + 'FROM charactertypes '. + 'WHERE id = ?', + 'iii', + $userId, $targetSeminaryId, + $type['id'] + ); + $charactertypeIds[$type['id']] = $this->db->getInsertId(); + } + + + return $charactertypeIds; + } + + /** * Delete a Charactertype. * diff --git a/models/MediaModel.inc b/models/MediaModel.inc index 5c7f5423..673ec773 100644 --- a/models/MediaModel.inc +++ b/models/MediaModel.inc @@ -133,6 +133,68 @@ return $data[0]; } + + + /** + * Copy all media from a Seminary. + * + * @param int $userId ID of creating user + * @param int $sourceSeminaryId ID of Seminary to copy from + * @param int $targetSeminaryId ID of Seminary to copy to + * @return array Mapping of Media-IDs from source Seminary to target Seminary + */ + public function copySeminaryMedia($userId, $sourceSeminaryId, $targetSeminaryId) + { + $seminaryMediaIds = array(); + $copiedFiles = array(); + + // Get all media from a Seminary + $seminaryMedia = $this->db->query( + 'SELECT id '. + 'FROM seminarymedia '. + 'WHERE seminary_id = ?', + 'i', + $sourceSeminaryId + ); + + // Copy each medium + try { + foreach($seminaryMedia as &$medium) + { + // Copy database record + $this->db->query( + 'INSERT INTO seminarymedia '. + '(created_user_id, seminary_id, name, url, description, mimetype) '. + 'SELECT ?, ?, name, url, description, mimetype '. + 'FROM seminarymedia '. + 'WHERE id = ?', + 'iii', + $userId, $targetSeminaryId, + $medium['id'] + ); + $seminaryMediaIds[$medium['id']] = $this->db->getInsertId(); + + // Copy file + $sourceFilename = ROOT.DS.\nre\configs\AppConfig::$dirs['seminarymedia'].DS.$medium['id']; + $targetFilename = ROOT.DS.\nre\configs\AppConfig::$dirs['seminarymedia'].DS.$seminaryMediaIds[$medium['id']]; + if(!copy($sourceFilename, $targetFilename)) { + throw new \hhu\z\exceptions\FileCopyException(error_get_last()); + } + $copiedFiles[] = $targetFilename; + } + } + catch(\hhu\z\exceptions\FileCopyException $e) { + // Cleanup + foreach($copiedFiles as $filename) { + unlink($filename); + } + throw $e; + } + + + // Return new media IDs + return $seminaryMediaIds; + } /** @@ -227,6 +289,29 @@ return $mediaId; } + + /** + * Copy an Avatar picture. + * + * @param int $userId ID of creating user + * @param int $seminaryMediaId ID of Seminary media to copy + */ + public function copyAvatarpicture($userId, $avatarpictureId) + { + $this->db->query( + 'INSERT INTO avatarpictures '. + '(seminarymedia_id, created_user_id) '. + 'VALUES '. + '(?, ?) '. + 'ON DUPLICATE KEY UPDATE '. + 'created_user_id = ?', + 'iii', + $avatarpictureId, + $userId, + $userId + ); + } + /** * Create a new Questgroup picture (Moodpic). @@ -280,6 +365,29 @@ $this->db->setAutocommit(true); return $mediaId; } + + + /** + * Copy a Questgroup picture. + * + * @param int $userId ID of creating user + * @param int $seminaryMediaId ID of Seminary media to copy + */ + public function copyQuestgroupspicture($userId, $questgroupspictureId) + { + $this->db->query( + 'INSERT INTO questgroupspictures '. + '(media_id, created_user_id) '. + 'VALUES '. + '(?, ?) '. + 'ON DUPLICATE KEY UPDATE '. + 'created_user_id = ?', + 'iii', + $questgroupspictureId, + $userId, + $userId + ); + } /** @@ -337,6 +445,30 @@ $this->db->setAutocommit(true); return $mediaId; } + + + + /** + * Copy media of a Quest. + * + * @param int $userId ID of creating user + * @param int $seminaryMediaId ID of Quest media to copy + */ + public function copyQuestsmedia($userId, $seminaryMediaId) + { + $this->db->query( + 'INSERT INTO questsmedia '. + '(media_id, created_user_id) '. + 'VALUES '. + '(?, ?) '. + 'ON DUPLICATE KEY UPDATE '. + 'created_user_id = ?', + 'iii', + $seminaryMediaId, + $userId, + $userId + ); + } /** @@ -445,6 +577,30 @@ $this->db->setAutocommit(true); return $mediaId; } + + + + /** + * Copy Achievement media. + * + * @param int $userId ID of creating user + * @param int $seminaryMediaId ID of Seminary media to copy + */ + public function copyAchievementMedia($userId, $seminaryMediaId) + { + $this->db->query( + 'INSERT INTO achievementsmedia '. + '(seminarymedia_id, created_user_id) '. + 'VALUES '. + '(?, ?) '. + 'ON DUPLICATE KEY UPDATE '. + 'created_user_id = ?', + 'iii', + $seminaryMediaId, + $userId, + $userId + ); + } @@ -465,8 +621,9 @@ $data = $this->db->query( 'SELECT id '. 'FROM seminarymedia '. - 'WHERE url = ?', - 's', + 'WHERE seminary_id = ? AND url = ?', + 'is', + $seminaryId, \nre\core\Linker::createLinkParam($filename) ); if(!empty($data)) { diff --git a/models/QuestgroupsModel.inc b/models/QuestgroupsModel.inc index f85a52f3..aa051bad 100644 --- a/models/QuestgroupsModel.inc +++ b/models/QuestgroupsModel.inc @@ -31,7 +31,7 @@ * * @var array */ - public $models = array('questgroupshierarchy', 'quests'); + public $models = array('questgroupshierarchy', 'questgrouptexts', 'quests', 'questtexts', 'media'); @@ -98,7 +98,7 @@ public function getQuestgroupsForSeminary($seminaryId) { return $this->db->query( - 'SELECT id, title, url, achievable_xps '. + 'SELECT id, title, url, questgroupspicture_id, achievable_xps '. 'FROM questgroups '. 'WHERE seminary_id = ? '. 'ORDER BY title ASC', @@ -396,6 +396,7 @@ } // XPs of child Questgroups + //var_dump($this->Questgroupshierarchy); $questgroupHierarchy = $this->Questgroupshierarchy->getHierarchyForQuestgroup($questgroupId); if(!empty($questgroupHierarchy)) { @@ -519,6 +520,79 @@ } + /** + * Copy Questgroupshierarchy of Questgroups from a Seminary. + * + * @param array $questgroupshierarchyIds Mapping of hierarchy-IDs from source Seminary to target Seminary + * @param array $questgroupIds Mapping of Questgroup-IDs from source Seminary to target Seminary + */ + public function copyQuestgroupsHierarchy($questgroupshierarchyIds, $questgroupIds) + { + foreach($questgroupIds as $sourceQuestgroupId => $targetQuestgroupId) + { + $hierarchy = $this->Questgroupshierarchy->getHierarchyForQuestgroup($sourceQuestgroupId); + if(!is_null($hierarchy)) + { + if(is_null($hierarchy['parent_questgroup_id'])) + { + $this->db->query( + 'INSERT INTO questgroups_questgroupshierarchy '. + '(questgroup_id, questgroupshierarchy_id, parent_questgroup_id, pos) '. + 'VALUES '. + '(?, ?, null, ?)', + 'iii', + $targetQuestgroupId, + $questgroupshierarchyIds[$hierarchy['id']], + $hierarchy['questgroup_pos'] + ); + } + else + { + $this->db->query( + 'INSERT INTO questgroups_questgroupshierarchy '. + '(questgroup_id, questgroupshierarchy_id, parent_questgroup_id, pos) '. + 'VALUES '. + '(?, ?, ?, ?)', + 'iiii', + $targetQuestgroupId, + $questgroupshierarchyIds[$hierarchy['id']], + $questgroupIds[$hierarchy['parent_questgroup_id']], + $hierarchy['questgroup_pos'] + ); + } + } + } + } + + + /** + * Copy all related Questgroups of Questtexts of a Seminary. + * + * @param array $questgroupIds Mapping of Questgroup-IDs from source Seminary to target Seminary + * @param array $questtextIds Mapping of Questtext-IDs from source Seminary to target Seminary + */ + public function copyRelatedQuestgroups($questgroupIds, $questtextIds) + { + foreach($questgroupIds as $sourceQuestgroupId => $targetQuestgroupId) + { + $questtexts = $this->Questtexts->getRelatedQuesttextsForQuestgroup($sourceQuestgroupId); + foreach($questtexts as &$questtext) + { + $this->db->query( + 'INSERT INTO questgroups_questtexts '. + '(questgroup_id, questtext_id, entry_text) '. + 'SELECT ?, ?, entry_text '. + 'FROM questgroups_questtexts '. + 'WHERE questgroup_id = ? AND questtext_id = ?', + 'iiii', + $targetQuestgroupId, $questtextIds[$questtext['id']], + $sourceQuestgroupId, $questtext['id'] + ); + } + } + } + + /** * Move a Questgroup up (decrement position) or down (increment * position). @@ -604,6 +678,61 @@ } + /** + * Copy Questgroups of Seminary. + * + * @throws \nre\exceptions\DatamodelException + * @param int $userId ID of creating user + * @param int $sourceSeminaryId ID of Seminary to copy Questgroups from + * @param int $targetSeminaryId ID of Seminary to copy Questgroups to + * @param array $questgroupshierarchyIds Mapping of hierarchy-IDs from source Seminary to target Seminary + * @param array $seminaryMediaIds Mapping of Seminary-media-IDs from source Seminary to target Seminary (optional) + * @return array Mapping of Questgroup-IDs from source Seminary to target Seminary + */ + public function copyQuestgroupsOfSeminary($userId, $sourceSeminaryId, $targetSeminaryId, $questgroupshierarchyIds, $seminaryMediaIds=null) + { + // Get Questgroups of source Seminary + $questgroupIds = array(); + $questgroups = $this->getQuestgroupsForSeminary($sourceSeminaryId); + foreach($questgroups as &$questgroup) + { + // Insert into target Seminary + $this->db->query( + 'INSERT INTO questgroups '. + '(created_user_id, seminary_id, title, url) '. + 'VALUES '. + '(?, ?, ?, ?)', + 'iiss', + $userId, + $targetSeminaryId, + $questgroup['title'], + $questgroup['url'] + ); + $questgroupIds[$questgroup['id']] = $this->db->getInsertId(); + + // Copy media + if(!is_null($seminaryMediaIds) && !is_null($questgroup['questgroupspicture_id'])) + { + $this->Media->copyQuestgroupspicture($userId, $seminaryMediaIds[$questgroup['questgroupspicture_id']]); + $this->db->query( + 'UPDATE questgroups '. + 'SET questgroupspicture_id = ? '. + 'WHERE id = ?', + 'ii', + $seminaryMediaIds[$questgroup['questgroupspicture_id']], + $questgroupIds[$questgroup['id']] + ); + } + + // Copy Questgroup texts + $this->Questgrouptexts->copyQuestgrouptexts($userId, $questgroup['id'], $questgroupIds[$questgroup['id']]); + } + + + return $questgroupIds; + } + + /** * Delete a Questgroup. * diff --git a/models/QuestgroupshierarchyModel.inc b/models/QuestgroupshierarchyModel.inc index 142c3694..072de8fc 100644 --- a/models/QuestgroupshierarchyModel.inc +++ b/models/QuestgroupshierarchyModel.inc @@ -302,7 +302,31 @@ } $this->db->setAutocommit(true); } - + + + /** + * Copy complete Questgroupshierarchy of a Seminary. + * + * @param int $userId ID of creating user + * @param int $sourceSeminaryId ID of Seminary to copy hierarchy from + * @param int $targetSeminaryId ID of Seminary to copy hierarchy to + * @return array Mapping of hierarchy-IDs from source Seminary to target Seminary + */ + public function copyQuestgroupshierarchy($userId, $sourceSeminaryId, $targetSeminaryId) + { + // Get Hierarchy of Seminary + $questgroupshierarchy = $this->getHierarchyOfSeminary($sourceSeminaryId); + + // Copy hierarchy + $hierarchyIds = array(); + foreach($questgroupshierarchy as $hierarchy) { + $this->copyHierarchy($userId, $sourceSeminaryId, $targetSeminaryId, $hierarchy, $hierarchyIds); + } + + + return $hierarchyIds; + } + /** * Delete a Questgroupshierarchy. @@ -313,6 +337,56 @@ { $this->db->query('DELETE FROM questgroupshierarchy WHERE id = ?', 'i', $questgroupshierarchyId); } + + + + + /** + * Copy a Questgroupshierarchy and its child hierarchy. + * + * @param int $userId ID of creating user + * @param int $sourceSeminaryId ID of Seminary to copy hierarchy from + * @param int $targetSeminaryId ID of Seminary to copy hierarchy to + * @param array $hierarchy Hierarchy to copy + * @return array $hierarchyIds Mapping of hierarchy IDs from source Seminary to target Seminary + */ + private function copyHierarchy($userId, $sourceSeminaryId, $targetSeminaryId, $hierarchy, &$hierarchyIds) + { + // insert for new seminary + if(is_null($hierarchy['parent_questgroupshierarchy_id'])) + { + $this->db->query( + 'INSERT INTO questgroupshierarchy '. + '(created_user_id, seminary_id, parent_questgroupshierarchy_id, pos, title_singular, title_plural, url) '. + 'SELECT ?, ?, null, pos, title_singular, title_plural, url '. + 'FROM questgroupshierarchy '. + 'WHERE id = ?', + 'iii', + $userId, $targetSeminaryId, + $hierarchy['id'] + ); + } + else + { + $this->db->query( + 'INSERT INTO questgroupshierarchy '. + '(created_user_id, seminary_id, parent_questgroupshierarchy_id, pos, title_singular, title_plural, url) '. + 'SELECT ?, ?, ?, pos, title_singular, title_plural, url '. + 'FROM questgroupshierarchy '. + 'WHERE id = ?', + 'iiii', + $userId, $targetSeminaryId, $hierarchyIds[$hierarchy['parent_questgroupshierarchy_id']], + $hierarchy['id'] + ); + } + $hierarchyIds[$hierarchy['id']] = $this->db->getInsertId(); + + // insert sub hierarchy + $childHierarchy = $this->getChildQuestgroupshierarchy($hierarchy['id']); + foreach($childHierarchy as $hierarchy) { + $this->copyHierarchy($userId, $sourceSeminaryId, $targetSeminaryId, $hierarchy, $hierarchyIds); + } + } } diff --git a/models/QuestgrouptextsModel.inc b/models/QuestgrouptextsModel.inc index 8abe42f6..6d678d92 100644 --- a/models/QuestgrouptextsModel.inc +++ b/models/QuestgrouptextsModel.inc @@ -19,12 +19,6 @@ */ class QuestgrouptextsModel extends \hhu\z\Model { - /** - * Required models - * - * @var array - */ - public $models = array('questgroupshierarchy', 'questgroups', 'quests', 'questtexts'); @@ -59,52 +53,6 @@ } - /** - * Get the first text of a Questgroup. - * - * @param int $questgroupId ID of a Questgroup - * @return string First text of this Questgroup or NULL - */ - public function getFirstQuestgroupText($questgroupId) - { - // Text of Questgroup itself - $questgroupTexts = $this->getQuestgroupTexts($questgroupId); - if(!empty($questgroupTexts)) { - return $questgroupTexts[0]['text']; - } - - // Text of first Quest - $quest = $this->Quests->getFirstQuestOfQuestgroup($questgroupId); - if(!is_null($quest)) - { - $questText = $this->Questtexts->getFirstQuestText($quest['id']); - if(!is_null($questText)) { - return $questText; - } - } - - // Text of ChildQuestgroups - $questgroupHierarchy = $this->Questgroupshierarchy->getHierarchyForQuestgroup($questgroupId); - $childQuestgroupshierarchy = $this->Questgroupshierarchy->getChildQuestgroupshierarchy($questgroupHierarchy['id']); - foreach($childQuestgroupshierarchy as &$hierarchy) - { - // Get Questgroups - $questgroups = $this->Questgroups->getQuestgroupsForHierarchy($hierarchy['id'], $questgroupId); - foreach($questgroups as &$group) - { - $childQuestgroupText = $this->getFirstQuestgroupText($group['id']); - if(!is_null($childQuestgroupText)) { - return $childQuestgroupText; - } - } - } - - - // No text found - return null; - } - - /** * Add a Questgroup text to a Questgroup. * @@ -155,6 +103,28 @@ } + /** + * Copy Questgroup texts from one Questgroup to another. + * + * @param $userId ID of copying user + * @param $sourceQuestgroupId ID of source Questgroup + * @param $targetQuestgroupId ID of target Questgroup + */ + public function copyQuestgrouptexts($userId, $sourceQuestgroupId, $targetQuestgroupId) + { + $this->db->query( + 'INSERT INTO questgrouptexts '. + '(created_user_id, questgroup_id, pos, text) '. + 'SELECT ?, ?, pos, text '. + 'FROM questgrouptexts '. + 'WHERE questgroup_id = ?', + 'iii', + $userId, $targetQuestgroupId, + $sourceQuestgroupId + ); + } + + /** * Delete a Questgroup text. * diff --git a/models/QuestsModel.inc b/models/QuestsModel.inc index 9fc60db2..8de1e60f 100644 --- a/models/QuestsModel.inc +++ b/models/QuestsModel.inc @@ -43,6 +43,13 @@ * @var int; */ const QUEST_STATUS_SOLVED = 3; + + /** + * Required models + * + * @var array + */ + public $models = array('questtypes', 'questtexts', 'media'); @@ -481,7 +488,6 @@ - /** * Mark a Quest for a Character. * @@ -676,6 +682,83 @@ } + /** + * Copy all Quests from a Seminary. + * + * @param int $userId ID of creating user + * @param int $seminaryId ID of Seminary to copy from + * @param array $questgroupIds Mapping of Questgroup-IDs from source Seminary to target Seminary + * @param array $seminaryMediaIds Mapping of Seminary-media-IDs from source Seminary to target Seminary (optional) + * @return array Mapping of Quest-IDs from source Seminary to target Seminary + */ + public function copyQuests($userId, $sourceSeminaryId, $questgroupIds, $seminaryMediaIds=null) + { + $questIds = array(); + $questtextIds = array(); + + // Get Quests + $quests = $this->getQuestsForSeminary($sourceSeminaryId); + + // Copy each Quest + foreach($quests as &$quest) + { + // Copy Quest + $this->db->query( + 'INSERT INTO quests '. + '(created_user_id, questgroup_id, questtype_id, title, url, xps, entry_text, wrong_text, task) '. + 'SELECT ?, ?, questtype_id, title, url, xps, entry_text, wrong_text, task '. + 'FROM quests '. + 'WHERE id = ?', + 'iii', + $userId, + $questgroupIds[$quest['questgroup_id']], + $quest['id'] + ); + $questIds[$quest['id']] = $this->db->getInsertId(); + + // Copy media + if(!is_null($seminaryMediaIds) && !is_null($quest['questsmedia_id'])) + { + $this->Media->copyQuestsmedia($userId, $seminaryMediaIds[$quest['questsmedia_id']]); + $this->db->query( + 'UPDATE quests '. + 'SET questsmedia_id = ? '. + 'WHERE id = ?', + 'ii', + $seminaryMediaIds[$quest['questsmedia_id']], + $questIds[$quest['id']] + ); + } + + // Copy texts + $questtextIds = array_merge( + $questtextIds, + $this->Questtexts->copyQuesttexts($userId, $quest['id'], $questIds[$quest['id']], $seminaryMediaIds) + ); + + // Copy content + $questtype = $this->Questtypes->getQuesttypeById($quest['questtype_id']); + if(!is_null($questtype['classname'])) + { + // Load Questtype Model + \hhu\z\models\QuesttypeModel::load($questtype['classname']); + + // Construct Questtype Model + $questtypeModel = \hhu\z\models\QuesttypeModel::factory($questtype['classname']); + + // Copy content + $questtypeModel->copyQuest($userId, $quest['id'], $questIds[$quest['id']], $seminaryMediaIds); + } + } + + + return array( + 'quests' => $questIds, + 'questtexts' => $questtextIds + ); + } + + /** * Delete a Quest of a Seminary. * diff --git a/models/QuesttextsModel.inc b/models/QuesttextsModel.inc index 257d95f2..4a0c2e0c 100644 --- a/models/QuesttextsModel.inc +++ b/models/QuesttextsModel.inc @@ -19,6 +19,12 @@ */ class QuesttextsModel extends \hhu\z\Model { + /** + * Required models + * + * @var array + */ + public $models = array('media'); @@ -304,6 +310,57 @@ $questtextId ); } + + + /** + * Copy Quest texts from one Quest to another. + * + * @param int $userId ID of copying user + * @param int $sourceQuestId ID of source Quest + * @param int $targetQuestId ID of target Quest + * @param array $seminaryMediaIds Mapping of Seminary-media-IDs from source Seminary to target Seminary (optional) + */ + public function copyQuesttexts($userId, $sourceQuestId, $targetQuestId, $seminaryMediaIds=null) + { + $questtextIds = array(); + + // Get Questtexts + $questtexts = $this->getQuesttextsOfQuest($sourceQuestId); + + // Copy each text + foreach($questtexts as &$text) + { + // Copy text + $this->db->query( + 'INSERT INTO questtexts '. + '(created_user_id, quest_id, questtexttype_id, pos, text, out_text, abort_text) '. + 'SELECT ?, ?, questtexttype_id, pos, text, out_text, abort_text '. + 'FROM questtexts '. + 'WHERE id = ?', + 'iii', + $userId, $targetQuestId, + $text['id'] + ); + $questtextIds[$text['id']] = $this->db->getInsertId(); + + // Copy media + if(!is_null($seminaryMediaIds) && !is_null($text['questsmedia_id'])) + { + $this->Media->copyQuestsmedia($userId, $seminaryMediaIds[$text['questsmedia_id']]); + $this->db->query( + 'UPDATE questtexts '. + 'SET questsmedia_id = ? '. + 'WHERE id = ?', + 'ii', + $seminaryMediaIds[$text['questsmedia_id']], + $questtextIds[$text['id']] + ); + } + } + + + return $questtextIds; + } /** diff --git a/models/QuesttopicsModel.inc b/models/QuesttopicsModel.inc index 4c7810bc..8950eacf 100644 --- a/models/QuesttopicsModel.inc +++ b/models/QuesttopicsModel.inc @@ -100,6 +100,81 @@ $seminaryId ); } + + + /** + * Copy all Questtopics and their subtopics of a Seminary. + * + * @param int $userId ID of creating user + * @param int $sourceSeminaryId ID of Seminary to copy from + * @param int $targetSeminaryId ID of Seminary to copy to + * @param array $questIds Mapping of Quest-IDs from source Seminary to target Seminary + * @return array Mapping of Questsubtopic-IDs from source Seminary to targetSeminary + */ + public function copyQuesttopicsOfSeminary($userId, $sourceSeminaryId, $targetSeminaryId, $questIds) + { + $questsubtopicIds = array(); + + // Get Questtopics + $questtopics = $this->getQuesttopicsForSeminary($sourceSeminaryId); + foreach($questtopics as &$questtopic) + { + // Copy Questtopic + $this->db->query( + 'INSERT INTO questtopics '. + '(created_user_id, seminary_id, title, url) '. + 'SELECT ?, ?, title, url '. + 'FROM questtopics '. + 'WHERE id = ?', + 'iii', + $userId, $targetSeminaryId, + $questtopic['id'] + ); + $targetQuesttopicId = $this->db->getInsertId(); + + // Get Questsubtopics + $questsubtopics = $this->getSubtopicsForQuesttopic($questtopic['id']); + foreach($questsubtopics as &$questsubtopic) + { + // Copy Questsubtopic + $this->db->query( + 'INSERT INTO questsubtopics '. + '(created_user_id, questtopic_id, title, url) '. + 'SELECT ?, ?, title, url '. + 'FROM questsubtopics '. + 'WHERE id = ?', + 'iii', + $userId, $targetQuesttopicId, + $questsubtopic['id'] + ); + $questsubtopicIds[$questsubtopic['id']] = $this->db->getInsertId(); + + // Get Quest links + $quests = $this->db->query( + 'SELECT quest_id '. + 'FROM quests_questsubtopics '. + 'WHERE questsubtopic_id = ?', + 'i', + $questsubtopic['id'] + ); + foreach($quests as &$quest) + { + $this->db->query( + 'INSERT INTO quests_questsubtopics '. + '(quest_id, questsubtopic_id) '. + 'VALUES '. + '(?, ?)', + 'ii', + $questIds[$quest['quest_id']], + $questsubtopicIds[$questsubtopic['id']] + ); + } + } + } + + + return $questsubtopicIds; + } /** diff --git a/models/SeminariesModel.inc b/models/SeminariesModel.inc index 0d41bd39..47173693 100644 --- a/models/SeminariesModel.inc +++ b/models/SeminariesModel.inc @@ -24,7 +24,7 @@ * * @var array */ - public $models = array('questgroupshierarchy', 'questgroups'); + public $models = array('questgroupshierarchy', 'questgroups', 'quests', 'questtopics', 'media', 'charactertypes', 'xplevels', 'avatars', 'achievements', 'charactergroups', 'charactergroupsquests', 'seminarycharacterfields'); @@ -200,6 +200,28 @@ $seminaryId ); } + + + /** + * (Re-) Calculate the amount of achievable XPs for a Seminary. + * + * @param int $seminaryId ID of Seminary to calculate XPs for + */ + public function calculateXPsForSeminary($seminaryId) + { + // Questgrouphierarchy and Questgroups + $questgroupshierarchy = $this->Questgroupshierarchy->getHierarchyOfSeminary($seminaryId); + foreach($questgroupshierarchy as &$hierarchy) + { + // Get Questgroups + $hierarchy['questgroups'] = $this->Questgroups->getQuestgroupsForHierarchy($hierarchy['id']); + foreach($hierarchy['questgroups'] as &$questgroup) + { + // Calculate achievable XPs + $this->Questgroups->calculateXPsForQuestgroup($questgroup['id']); + } + } + } /** @@ -225,6 +247,122 @@ $seminaryId ); } + + + /** + * Copy a Seminary and its content. + * + * @param int $userId ID of copying user + * @param int $sourceSeminaryId ID of Seminary to copy + * @param string $title Title of new Seminary + * @param string $course Course of now Seminary + * @param string $description Description of new Seminary + * @param boolean $copySeminaryfields Whether to copy Seminary Character fields of not + * @param boolean $copyMedia Whether to copy media or not + * @param boolean $copyQuestgroupshierarchy Whether to copy Questgroupshierarchy or not + * @param boolean $copyQuestgroups Whether to copy Questgroups or not + * @param boolean $copyQuests Whether to copy Quests or not + * @param boolean $copyQuesttopics Whether to copy Quest topics or not + * @param boolean $copyCharactertypes Whether to copy Charactertypes or not + * @param boolean $copyXPlevels Whether to copy XP-levels or not + * @param boolean $copyAvatars Whether to copy Avatars or not + * @param boolean $copyAchievements Whether to copy Achievements or not + * @param boolean $copyCharactergroupsgroups Whether to copy Character groups-groups or not + * @param boolean $copyCharactergroupsquests Whether to copy Character groups Quests or not + * @return ID of newly created Seminary + */ + public function copySeminary($userId, $sourceSeminaryId, $title, $course, $description, $copySeminaryfields, $copyMedia, $copyQuestgroupshierarchy, $copyQuestgroups, $copyQuests, $copyQuesttopics, $copyCharactertypes, $copyXPlevels, $copyAvatars, $copyAchievements, $copyCharactergroupsgroups, $copyCharactergroupsquests) + { + $this->db->setAutocommit(false); + try { + // Create new Seminary + $targetSeminaryId = $this->createSeminary($userId, $title, $course, $description); + + // Copy Seminary fields + if($copySeminaryfields) { + $this->Seminarycharacterfields->copyFieldsOfSeminary($userId, $sourceSeminaryId, $targetSeminaryId); + } + + // Copy media + $seminaryMediaIds = null; + if($copyMedia) { + $seminaryMediaIds = $this->Media->copySeminaryMedia($userId, $sourceSeminaryId, $targetSeminaryId); + } + + // Copy Quest content + $questIds = null; + $questgroupIds = null; + // Questgroupshierarchy + if($copyQuestgroupshierarchy) + { + $questgroupshierarchyIds = $this->Questgroupshierarchy->copyQuestgroupshierarchy($userId, $sourceSeminaryId, $targetSeminaryId); + // Questgroups + if($copyQuestgroups) + { + $questgroupIds = $this->Questgroups->copyQuestgroupsOfSeminary($userId, $sourceSeminaryId, $targetSeminaryId, $questgroupshierarchyIds, $seminaryMediaIds); + $this->Questgroups->copyQuestgroupsHierarchy($questgroupshierarchyIds, $questgroupIds); + // Quests + if($copyQuests) + { + $questAndTextIds = $this->Quests->copyQuests($userId, $sourceSeminaryId, $questgroupIds, $seminaryMediaIds); + $questIds = $questAndTextIds['quests']; + $questtextIds = $questAndTextIds['questtexts']; + $this->Questgroups->copyRelatedQuestgroups($questgroupIds, $questtextIds); + // Questtopics + if($copyQuesttopics) { + $questsubtopicIds = $this->Questtopics->copyQuesttopicsOfSeminary($userId, $sourceSeminaryId, $targetSeminaryId, $questIds); + } + } + } + } + + // Copy Character content + // Charactertypes + if($copyCharactertypes) + { + $charactertypeIds = $this->Charactertypes->copyCharactertypesOfSeminary($userId, $sourceSeminaryId, $targetSeminaryId); + // XP-levels + if($copyXPlevels) + { + $xplevelIds = $this->Xplevels->copyXPLevelsOfSeminary($userId, $sourceSeminaryId, $targetSeminaryId); + // Avatars + if($copyAvatars && !is_null($seminaryMediaIds)) { + $this->Avatars->copyAvatars($userId, $charactertypeIds, $xplevelIds, $seminaryMediaIds); + } + } + } + + // Copy Achievements + if($copyAchievements && !is_null($seminaryMediaIds)) { + $this->Achievements->copyAchievementsOfSeminary($userId, $sourceSeminaryId, $targetSeminaryId, $seminaryMediaIds, $questIds); + } + + // Copy Charactergroups content + // Charactergroupsgroups + if($copyCharactergroupsgroups) + { + $characterGroupsgroupIds = $this->Charactergroups->copyGroupsgroupsOfSeminary($userId, $sourceSeminaryId, $targetSeminaryId); + // Copy Charactergroupsquests + if($copyCharactergroupsquests &!is_null($questgroupIds)) { + $this->Charactergroupsquests->copyQuestsOfSeminary($userId, $characterGroupsgroupIds, $questgroupIds, $seminaryMediaIds); + } + } + + // Recalculate XPs + $this->calculateXPsForSeminary($targetSeminaryId); + + $this->db->commit(); + } + catch(\Exception $e) { + $this->db->rollback(); + $this->db->setAutocommit(true); + throw $e; + } + $this->db->setAutocommit(true); + + + return $targetSeminaryId; + } /** @@ -236,7 +374,7 @@ { $this->db->query('DELETE FROM seminaries WHERE id = ?', 'i', $seminaryId); } - + } ?> diff --git a/models/SeminarycharacterfieldsModel.inc b/models/SeminarycharacterfieldsModel.inc index 8286e692..78dc3c18 100644 --- a/models/SeminarycharacterfieldsModel.inc +++ b/models/SeminarycharacterfieldsModel.inc @@ -123,6 +123,28 @@ $characterId ); } + + + /** + * Copy all Character fields of a Seminary. + * + * @param int $userId ID of copying user + * @param int $sourceSeminaryId ID of Seminary to copy from + * @param int $targetSeminaryId ID of Seminary to copy to + */ + public function copyFieldsOfSeminary($userId, $sourceSeminaryId, $targetSeminaryId) + { + $this->db->query( + 'INSERT INTO seminarycharacterfields '. + '(created_user_id, seminary_id, pos, title, url, seminarycharacterfieldtype_id, regex, required) '. + 'SELECT ?, ?, pos, title, url, seminarycharacterfieldtype_id, regex, required '. + 'FROM seminarycharacterfields '. + 'WHERE seminary_id = ?', + 'iii', + $userId, $targetSeminaryId, + $sourceSeminaryId + ); + } } diff --git a/models/XplevelsModel.inc b/models/XplevelsModel.inc index c0df02b2..0d7489b0 100644 --- a/models/XplevelsModel.inc +++ b/models/XplevelsModel.inc @@ -161,6 +161,42 @@ ); } + + /** + * Copy all XP-levels of a Seminary. + * + * @param int $userId ID of copying user + * @param int $sourceSeminaryId ID of Seminary to copy from + * @param int $targetSeminaryId ID of Seminary to copy to + * @param array Mapping of XP-level-IDs from source Seminary to targetSeminary + */ + public function copyXPLevelsOfSeminary($userId, $sourceSeminaryId, $targetSeminaryId) + { + $xplevelIds = array(); + + // Get XP-levels + $xplevels = $this->getXPLevelsForSeminary($sourceSeminaryId); + + // Copy each XP-level + foreach($xplevels as &$level) + { + $this->db->query( + 'INSERT INTO xplevels '. + '(created_user_id, seminary_id, xps, level, name) '. + 'SELECT ?, ?, xps, level, name '. + 'FROM xplevels '. + 'WHERE id = ?', + 'iii', + $userId, $targetSeminaryId, + $level['id'] + ); + $xplevelIds[$level['id']] = $this->db->getInsertId(); + } + + + return $xplevelIds; + } + /** * Delete a XP-level. diff --git a/questtypes/bossfight/BossfightQuesttypeModel.inc b/questtypes/bossfight/BossfightQuesttypeModel.inc index ea2ad7db..318a2933 100644 --- a/questtypes/bossfight/BossfightQuesttypeModel.inc +++ b/questtypes/bossfight/BossfightQuesttypeModel.inc @@ -19,10 +19,55 @@ */ class BossfightQuesttypeModel extends \hhu\z\models\QuesttypeModel { + /** + * Required models + * + * @var array + */ + public $models = array('media'); + /** + * Copy a Quest + * + * @param int $userId ID of creating user + * @param int $sourceQuestId ID of Quest to copy from + * @param int $targetQuestId ID of Quest to copy to + * @param int $seminaryMediaIds Mapping of SeminaryMedia-IDs from source Seminary to targetSeminary + */ + public function copyQuest($userId, $sourceQuestId, $targetQuestId, $seminaryMediaIds) + { + // Check Seminary media + if(is_null($seminaryMediaIds)) { + return; + } + + // Get boss fight + $bossfight = $this->getBossFight($sourceQuestId); + + // Copy media + $this->Media->copyQuestsmedia($userId, $seminaryMediaIds[$bossfight['boss_seminarymedia_id']]); + + // Copy boss fight + $this->db->query( + 'INSERT INTO questtypes_bossfight '. + '(quest_id, created_user_id, bossname, boss_seminarymedia_id, lives_character, lives_boss) '. + 'SELECT ?, ?, bossname, ?, lives_character, lives_boss '. + 'FROM questtypes_bossfight '. + 'WHERE quest_id = ?', + 'iiii', + $targetQuestId, $userId, $seminaryMediaIds[$bossfight['boss_seminarymedia_id']], + $sourceQuestId + ); + + // Copy stages + $stage = $this->getFirstStage($sourceQuestId); + $this->copyStage($userId, $targetQuestId, $stage); + } + + /** * Get a Boss-Fight. * @@ -57,7 +102,7 @@ public function getFirstStage($questId) { $data = $this->db->query( - 'SELECT id, text, question, livedrain_character, livedrain_boss '. + 'SELECT id, parent_stage_id, text, question, livedrain_character, livedrain_boss '. 'FROM questtypes_bossfight_stages '. 'WHERE questtypes_bossfight_quest_id = ? AND parent_stage_id IS NULL', 'i', @@ -105,7 +150,7 @@ public function getChildStages($parentStageId) { return $this->db->query( - 'SELECT id, text, question, livedrain_character, livedrain_boss '. + 'SELECT id, parent_stage_id, text, question, livedrain_character, livedrain_boss '. 'FROM questtypes_bossfight_stages '. 'WHERE parent_stage_id = ?', 'i', @@ -177,6 +222,55 @@ return (!empty($data)); } + + + + + /** + * Copy a Bossfight stage and its child-stages. + * + * @param int $userId ID of copying user + * @param int $targetQuestId ID of Quest to copy to + * @param array $stage Data of stage to copy + * @param array $stageIds Mapping of Stage-IDs from source Seminary to target Seminary + */ + private function copyStage($userId, $targetQuestId, $stage, $stageIds=array()) + { + // Copy stage + if(is_null($stage['parent_stage_id'])) + { + $this->db->query( + 'INSERT INTO questtypes_bossfight_stages '. + '(questtypes_bossfight_quest_id, text, question, livedrain_character, livedrain_boss) '. + 'SELECT ?, text, question, livedrain_character, livedrain_boss '. + 'FROM questtypes_bossfight_stages '. + 'WHERE id = ?', + 'ii', + $targetQuestId, + $stage['id'] + ); + } + else + { + $this->db->query( + 'INSERT INTO questtypes_bossfight_stages '. + '(questtypes_bossfight_quest_id, parent_stage_id, text, question, livedrain_character, livedrain_boss) '. + 'SELECT ?, ?, text, question, livedrain_character, livedrain_boss '. + 'FROM questtypes_bossfight_stages '. + 'WHERE id = ?', + 'iii', + $targetQuestId, $stageIds[$stage['parent_stage_id']], + $stage['id'] + ); + } + $stageIds[$stage['id']] = $this->db->getInsertId(); + + // Copy child stages + $childStages = $this->getChildStages($stage['id']); + foreach($childStages as $childStage) { + $this->copyStage($userId, $targetQuestId, $childStage, $stageIds); + } + } } diff --git a/questtypes/choiceinput/ChoiceinputQuesttypeModel.inc b/questtypes/choiceinput/ChoiceinputQuesttypeModel.inc index 2c7151bf..d683449e 100644 --- a/questtypes/choiceinput/ChoiceinputQuesttypeModel.inc +++ b/questtypes/choiceinput/ChoiceinputQuesttypeModel.inc @@ -24,6 +24,79 @@ + /** + * Copy a Quest + * + * @param int $userId ID of creating user + * @param int $sourceQuestId ID of Quest to copy from + * @param int $targetQuestId ID of Quest to copy to + * @param int $seminaryMediaIds Mapping of SeminaryMedia-IDs from source Seminary to targetSeminary + */ + public function copyQuest($userId, $sourceQuestId, $targetQuestId, $seminaryMediaIds) + { + // Copy choiceinput + $this->db->query( + 'INSERT INTO questtypes_choiceinput '. + '(quest_id, created_user_id, text) '. + 'SELECT ?, ?, text '. + 'FROM questtypes_choiceinput '. + 'WHERE quest_id = ?', + 'iii', + $targetQuestId, $userId, + $sourceQuestId + ); + + // Copy lists + $lists = $this->getChoiceinputLists($sourceQuestId); + foreach($lists as &$list) + { + // Copy list + $this->db->query( + 'INSERT INTO questtypes_choiceinput_lists '. + '(questtypes_choiceinput_quest_id, number) '. + 'SELECT ?, number '. + 'FROM questtypes_choiceinput_lists '. + 'WHERE id = ?', + 'ii', + $targetQuestId, + $list['id'] + ); + $targetListId = $this->db->getInsertId(); + + // Copy choices + $choiceIds = array(); + $choices = $this->getChoiceinputChoices($list['id']); + foreach($choices as $choice) + { + $this->db->query( + 'INSERT INTO questtypes_choiceinput_choices '. + '(questtypes_choiceinput_list_id, pos, text) '. + 'SELECT ?, pos, text '. + 'FROM questtypes_choiceinput_choices '. + 'WHERE id = ?', + 'ii', + $targetListId, + $choice['id'] + ); + $choiceIds[$choice['id']] = $this->db->getInsertId(); + } + + // Set correct choice + if(!is_null($list['questtypes_choiceinput_choice_id'])) + { + $this->db->query( + 'UPDATE questtypes_choiceinput_lists '. + 'SET questtypes_choiceinput_choice_id = ? '. + 'WHERE id = ?', + 'ii', + $choiceIds[$list['questtypes_choiceinput_choice_id']], + $targetListId + ); + } + } + } + + /** * Get choiceinput-text for a Quest. * diff --git a/questtypes/crossword/CrosswordQuesttypeModel.inc b/questtypes/crossword/CrosswordQuesttypeModel.inc index 23da2daa..d8862425 100644 --- a/questtypes/crossword/CrosswordQuesttypeModel.inc +++ b/questtypes/crossword/CrosswordQuesttypeModel.inc @@ -23,6 +23,30 @@ + /** + * Copy a Quest + * + * @param int $userId ID of creating user + * @param int $sourceQuestId ID of Quest to copy from + * @param int $targetQuestId ID of Quest to copy to + * @param int $seminaryMediaIds Mapping of SeminaryMedia-IDs from source Seminary to targetSeminary + */ + public function copyQuest($userId, $sourceQuestId, $targetQuestId, $seminaryMediaIds) + { + // Copy words + $this->db->query( + 'INSERT INTO questtypes_crossword_words '. + '(quest_id, question, word, vertical, pos_x, pos_y) '. + 'SELECT ?, question, word, vertical, pos_x, pos_y '. + 'FROM questtypes_crossword_words '. + 'WHERE quest_id = ?', + 'ii', + $targetQuestId, + $sourceQuestId + ); + } + + /** * Get all words for a crossword-Quest. * diff --git a/questtypes/dragndrop/DragndropQuesttypeModel.inc b/questtypes/dragndrop/DragndropQuesttypeModel.inc index 7783f889..cc3db7e0 100644 --- a/questtypes/dragndrop/DragndropQuesttypeModel.inc +++ b/questtypes/dragndrop/DragndropQuesttypeModel.inc @@ -19,10 +19,115 @@ */ class DragndropQuesttypeModel extends \hhu\z\models\QuesttypeModel { + /** + * Required models + * + * @var array + */ + public $models = array('media'); + /** + * Copy a Quest + * + * @param int $userId ID of creating user + * @param int $sourceQuestId ID of Quest to copy from + * @param int $targetQuestId ID of Quest to copy to + * @param int $seminaryMediaIds Mapping of SeminaryMedia-IDs from source Seminary to targetSeminary + */ + public function copyQuest($userId, $sourceQuestId, $targetQuestId, $seminaryMediaIds) + { + // Check Seminary media + if(is_null($seminaryMediaIds)) { + return; + } + + // Get Dragndrop + $dragndrop = $this->getDragndrop($sourceQuestId); + + // Copy media + $this->Media->copyQuestsmedia($userId, $seminaryMediaIds[$dragndrop['questmedia_id']]); + + // Copy dran&drop + $this->db->query( + 'INSERT INTO questtypes_dragndrop '. + '(quest_id, created_user_id, questmedia_id, width, height) '. + 'SELECT ?, ?, ?, width, height '. + 'FROM questtypes_dragndrop '. + 'WHERE quest_id = ?', + 'iiii', + $targetQuestId, $userId, $seminaryMediaIds[$dragndrop['questmedia_id']], + $sourceQuestId + ); + + // Copy drags + $dragIds = array(); + $drags = $this->getDrags($sourceQuestId); + foreach($drags as &$drag) + { + // Copy media + $this->Media->copyQuestsmedia($userId, $seminaryMediaIds[$drag['questmedia_id']]); + + // Copy drag + $this->db->query( + 'INSERT INTO questtypes_dragndrop_drags '. + '(questtypes_dragndrop_id, questmedia_id) '. + 'SELECT ?, ? '. + 'FROM questtypes_dragndrop_drags '. + 'WHERE id = ?', + 'iii', + $targetQuestId, $seminaryMediaIds[$drag['questmedia_id']], + $drag['id'] + ); + $dragIds[$drag['id']] = $this->db->getInsertId(); + } + + // Copy drops + $dropIds = array(); + $drops = $this->getDrops($sourceQuestId); + foreach($drops as &$drop) + { + // Copy drop + $this->db->query( + 'INSERT INTO questtypes_dragndrop_drops '. + '(questtypes_dragndrop_id, top, `left`, width, height) '. + 'SELECT ?, top, `left`, width, height '. + 'FROM questtypes_dragndrop_drops '. + 'WHERE id = ?', + 'ii', + $targetQuestId, + $drop['id'] + ); + $dropIds[$drop['id']] = $this->db->getInsertId(); + + // Link drags and drops + $links = $this->db->query( + 'SELECT questtypes_dragndrop_drag_id '. + 'FROM questtypes_dragndrop_drops_drags '. + 'WHERE questtypes_dragndrop_drop_id = ?', + 'i', + $drop['id'] + ); + foreach($links as $link) + { + $this->db->query( + 'INSERT INTO questtypes_dragndrop_drops_drags '. + '(questtypes_dragndrop_drop_id, questtypes_dragndrop_drag_id, created_user_id) '. + 'VALUES '. + '(?, ?, ?)', + 'iii', + $dropIds[$drop['id']], + $dragIds[$link['questtypes_dragndrop_drag_id']], + $userId + ); + } + } + } + + + /** * Get Drag&Drop-field. * diff --git a/questtypes/multiplechoice/MultiplechoiceQuesttypeModel.inc b/questtypes/multiplechoice/MultiplechoiceQuesttypeModel.inc index 5f91d360..63be40f9 100644 --- a/questtypes/multiplechoice/MultiplechoiceQuesttypeModel.inc +++ b/questtypes/multiplechoice/MultiplechoiceQuesttypeModel.inc @@ -23,6 +23,50 @@ + /** + * Copy a Quest + * + * @param int $userId ID of creating user + * @param int $sourceQuestId ID of Quest to copy from + * @param int $targetQuestId ID of Quest to copy to + * @param int $seminaryMediaIds Mapping of SeminaryMedia-IDs from source Seminary to targetSeminary + */ + public function copyQuest($userId, $sourceQuestId, $targetQuestId, $seminaryMediaIds) + { + // Get questions + $questions = $this->getQuestionsOfQuest($sourceQuestId); + + // Copy each question + foreach($questions as &$question) + { + // Copy question + $this->db->query( + 'INSERT INTO questtypes_multiplechoice '. + '(created_user_id, quest_id, pos, question) '. + 'SELECT ?, ?, pos, question '. + 'FROM questtypes_multiplechoice '. + 'WHERE id = ?', + 'iii', + $userId, $targetQuestId, + $question['id'] + ); + $targetQuestionId = $this->db->getInsertId(); + + // Copy answers + $this->db->query( + 'INSERT INTO questtypes_multiplechoice_answers '. + '(created_user_id, questtypes_multiplechoice_id, pos, answer, tick) '. + 'SELECT ?, ?, pos, answer, tick '. + 'FROM questtypes_multiplechoice_answers '. + 'WHERE questtypes_multiplechoice_id = ?', + 'iii', + $userId, $targetQuestionId, + $question['id'] + ); + } + } + + /** * Get the count of multiple choice questions for a Quest. * diff --git a/questtypes/submit/SubmitQuesttypeModel.inc b/questtypes/submit/SubmitQuesttypeModel.inc index 5a00966b..e9aeeb8c 100644 --- a/questtypes/submit/SubmitQuesttypeModel.inc +++ b/questtypes/submit/SubmitQuesttypeModel.inc @@ -29,6 +29,19 @@ + /** + * Copy a Quest + * + * @param int $userId ID of creating user + * @param int $sourceQuestId ID of Quest to copy from + * @param int $targetQuestId ID of Quest to copy to + * @param int $seminaryMediaIds Mapping of SeminaryMedia-IDs from source Seminary to targetSeminary + */ + public function copyQuest($userId, $sourceQuestId, $targetQuestId, $seminaryMediaIds) + { + } + + /** * Save Character’s submitted upload. * diff --git a/questtypes/textinput/TextinputQuesttypeModel.inc b/questtypes/textinput/TextinputQuesttypeModel.inc index b503701d..c1e902c7 100644 --- a/questtypes/textinput/TextinputQuesttypeModel.inc +++ b/questtypes/textinput/TextinputQuesttypeModel.inc @@ -23,6 +23,42 @@ + /** + * Copy a Quest + * + * @param int $userId ID of creating user + * @param int $sourceQuestId ID of Quest to copy from + * @param int $targetQuestId ID of Quest to copy to + * @param int $seminaryMediaIds Mapping of SeminaryMedia-IDs from source Seminary to targetSeminary + */ + public function copyQuest($userId, $sourceQuestId, $targetQuestId, $seminaryMediaIds) + { + // Copy textinput + $this->db->query( + 'INSERT INTO questtypes_textinput '. + '(quest_id, created_user_id, text) '. + 'SELECT ?, ?, text '. + 'FROM questtypes_textinput '. + 'WHERE quest_id = ?', + 'iii', + $targetQuestId, $userId, + $sourceQuestId + ); + + // Copy fields + $this->db->query( + 'INSERT INTO questtypes_textinput_fields '. + '(questtypes_textinput_quest_id, number, questtypes_textinput_fieldsize_id, regex) '. + 'SELECT ?, number, questtypes_textinput_fieldsize_id, regex '. + 'FROM questtypes_textinput_fields '. + 'WHERE questtypes_textinput_quest_id = ?', + 'ii', + $targetQuestId, + $sourceQuestId + ); + } + + /** * Get textinput-text for a Quest. * diff --git a/views/html/seminaries/copy.tpl b/views/html/seminaries/copy.tpl new file mode 100644 index 00000000..39187f50 --- /dev/null +++ b/views/html/seminaries/copy.tpl @@ -0,0 +1,116 @@ + +

+ +
+ + + +

+ +

+ + getNestedError()['message'])?> + + getMessage())?> + +

+ + +
    + &$settings) : ?> +
  • +
      + $value) : ?> +
    • + +
    • + +
    +
  • + +
+ +
+
+ + />
+ + />
+
+
+ + checked="checked" /> + + checked="checked" /> + + checked="checked" /> + +
+ checked="checked" /> + +
+ checked="checked" /> + +
+ checked="checked" /> + +
+
+
+ checked="checked" /> + +
+ checked="checked" /> + +
+ checked="checked" /> + +
+
+ checked="checked" /> + + checked="checked" /> + +
+ checked="checked" /> + +
+
+ +
diff --git a/views/html/seminaries/seminary.tpl b/views/html/seminaries/seminary.tpl index 3ebecbce..ae762765 100644 --- a/views/html/seminaries/seminary.tpl +++ b/views/html/seminaries/seminary.tpl @@ -8,6 +8,7 @@ diff --git a/www/css/desktop.css b/www/css/desktop.css index 1a154451..423cd5a7 100644 --- a/www/css/desktop.css +++ b/www/css/desktop.css @@ -181,6 +181,9 @@ input[type="submit"][disabled]{text-shadow:1px 2px #d48c4e;background:#f9ac69;bo .logreg textarea,.logreg select{width:100%;margin:5px 0 15px;-webkit-box-sizing: border-box;-moz-box-sizing:border-box;box-sizing:border-box} .logreg textarea{height:150px} .logreg .cta{display:block} +.logreg input[type="checkbox"]{margin:0} +.logreg input[type="checkbox"] + label{display:inline;} +.logreg input[type="checkbox"] + label:after{content:"\A";white-space:pre} .inlbl input{display:inline;margin:0 10px 0 0} .inlbl label{display:inline} @@ -453,3 +456,7 @@ aside .charstats{background:#f7f5f2;border-radius:3px;padding:10px 0;margin-top: aside .charstats li{font-size:.875em;padding:2px 0} aside .cranks li:nth-child(odd){background:#f7f5f2} } + + +div.cond{display:none;margin-left:15px} +input[type="checkbox"]:checked + label + div.cond{display:block}