From b2d00bc624c3359144ac492ff8a4e2397ba37dd6 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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 LxM}l?I9Emhh=k1p delta 8019 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 KH$O^nVgvx}yFpO^ diff --git a/locale/de_DE/LC_MESSAGES/The Legend of Z.po b/locale/de_DE/LC_MESSAGES/The Legend of Z.po index db9566b3..f3ca15bb 100644 --- a/locale/de_DE/LC_MESSAGES/The Legend of Z.po +++ b/locale/de_DE/LC_MESSAGES/The Legend of Z.po @@ -1,15 +1,15 @@ msgid "" msgstr "" "Project-Id-Version: The Legend of Z\n" -"POT-Creation-Date: 2014-08-29 15:17+0100\n" -"PO-Revision-Date: 2014-08-29 15:17+0100\n" +"POT-Creation-Date: 2015-03-21 14:54+0100\n" +"PO-Revision-Date: 2015-03-21 14:55+0100\n" "Last-Translator: \n" "Language-Team: \n" "Language: de_DE\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.6.7\n" +"X-Generator: Poedit 1.7.4\n" "X-Poedit-Basepath: ../../../\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Poedit-SourceCharset: UTF-8\n" @@ -17,8 +17,8 @@ msgstr "" "X-Poedit-SearchPath-1: questtypes\n" "X-Poedit-SearchPath-2: controllers\n" -#: controllers/CharactersController.inc:401 -#: controllers/UsersController.inc:320 views/ajax/characters/index.tpl:10 +#: controllers/CharactersController.inc:402 +#: controllers/UsersController.inc:322 views/ajax/characters/index.tpl:10 #: views/ajax/users/index.tpl:10 views/html/characters/index.tpl:48 #: views/html/characters/manage.tpl:35 views/html/characters/manage.tpl:50 #: views/html/characters/manage.tpl:58 views/html/userroles/user.tpl:5 @@ -27,8 +27,8 @@ msgstr "" msgid "Admin" msgstr "Administrator" -#: controllers/CharactersController.inc:407 -#: controllers/UsersController.inc:326 views/ajax/characters/index.tpl:12 +#: controllers/CharactersController.inc:408 +#: controllers/UsersController.inc:328 views/ajax/characters/index.tpl:12 #: views/ajax/users/index.tpl:12 views/html/characters/index.tpl:49 #: views/html/characters/manage.tpl:36 views/html/characters/manage.tpl:51 #: views/html/characters/manage.tpl:59 views/html/userroles/user.tpl:7 @@ -37,8 +37,8 @@ msgstr "Administrator" msgid "Moderator" msgstr "Moderator" -#: controllers/CharactersController.inc:413 -#: controllers/UsersController.inc:332 views/ajax/characters/index.tpl:14 +#: controllers/CharactersController.inc:414 +#: controllers/UsersController.inc:334 views/ajax/characters/index.tpl:14 #: views/ajax/users/index.tpl:14 views/html/characters/index.tpl:50 #: views/html/characters/manage.tpl:37 views/html/characters/manage.tpl:53 #: views/html/characters/manage.tpl:61 views/html/userroles/user.tpl:9 @@ -51,19 +51,19 @@ msgstr "Benutzer" msgid "New user registration" msgstr "Neue Benutzerregistrierung" -#: controllers/MailController.inc:74 +#: controllers/MailController.inc:75 msgid "New Character registration" msgstr "Neue Charakterregistrierung" -#: controllers/MailController.inc:99 +#: controllers/MailController.inc:100 msgid "New Character submission" msgstr "Neuer Lösungsvorschlag" -#: controllers/MailController.inc:124 +#: controllers/MailController.inc:125 msgid "Character submission approved" msgstr "Lösungsvorschlag bewertet" -#: controllers/QuestsController.inc:1287 +#: controllers/QuestsController.inc:1249 #: questtypes/submit/html/submission.tpl:30 #: views/html/achievements/conditions.tpl:54 #: views/html/achievements/conditions.tpl:121 views/html/quests/quest.tpl:54 @@ -71,6 +71,55 @@ msgstr "Lösungsvorschlag bewertet" msgid "solved" msgstr "Richtig!" +#: controllers/SeminariesController.inc:409 +msgid "Copy" +msgstr "Kopie" + +#: questtypes/bossfight/html/edittask.tpl:3 +msgid "Boss-Fight" +msgstr "" + +#: questtypes/bossfight/html/edittask.tpl:4 +msgid "Boss name" +msgstr "" + +#: questtypes/bossfight/html/edittask.tpl:6 +msgid "Boss image" +msgstr "" + +#: questtypes/bossfight/html/edittask.tpl:8 +msgid "Boss lives" +msgstr "" + +#: questtypes/bossfight/html/edittask.tpl:10 +msgid "Character lives" +msgstr "" + +#: questtypes/bossfight/html/edittask.tpl:14 +msgid "Stages" +msgstr "" + +#: questtypes/bossfight/html/edittask.tpl:17 +#: questtypes/choiceinput/html/edittask.tpl:83 +#: questtypes/multiplechoice/html/edittask.tpl:79 +#: questtypes/textinput/html/edittask.tpl:44 +#: views/html/achievements/conditions.tpl:151 +#: views/html/achievements/create.tpl:109 views/html/achievements/edit.tpl:112 +#: views/html/charactergroupsquests/manage.tpl:66 +#: views/html/charactertypes/edit.tpl:124 views/html/library/edit.tpl:46 +#: views/html/library/edit.tpl:86 views/html/quests/edit.tpl:114 +#: views/html/users/edit.tpl:105 views/html/xplevels/manage.tpl:49 +msgid "save" +msgstr "speichern" + +#: questtypes/bossfight/html/edittask.tpl:26 +msgid "Character" +msgstr "Charakter" + +#: questtypes/bossfight/html/edittask.tpl:26 +msgid "Boss" +msgstr "" + #: questtypes/bossfight/html/quest.tpl:11 #: questtypes/bossfight/html/quest.tpl:24 #: questtypes/bossfight/html/submission.tpl:21 @@ -78,7 +127,7 @@ msgstr "Richtig!" msgid "lost" msgstr "verloren" -#: questtypes/bossfight/html/quest.tpl:41 views/html/quests/quest.tpl:129 +#: questtypes/bossfight/html/quest.tpl:41 views/html/quests/quest.tpl:133 msgid "Choose" msgstr "Wählen" @@ -132,18 +181,6 @@ msgstr "Auswahleingaben" msgid "Preview" msgstr "Vorschau" -#: questtypes/choiceinput/html/edittask.tpl:83 -#: questtypes/multiplechoice/html/edittask.tpl:79 -#: questtypes/textinput/html/edittask.tpl:44 -#: views/html/achievements/conditions.tpl:151 -#: views/html/achievements/create.tpl:109 views/html/achievements/edit.tpl:112 -#: views/html/charactergroupsquests/manage.tpl:66 -#: views/html/charactertypes/edit.tpl:124 views/html/library/edit.tpl:46 -#: views/html/library/edit.tpl:86 views/html/quests/edit.tpl:114 -#: views/html/users/edit.tpl:105 views/html/xplevels/manage.tpl:49 -msgid "save" -msgstr "speichern" - #: questtypes/crossword/html/quest.tpl:22 #: questtypes/crossword/html/submission.tpl:22 msgid "vertical" @@ -383,7 +420,8 @@ msgstr "Fehler" #: views/html/achievements/conditions.tpl:8 #: views/html/achievements/create.tpl:8 views/html/achievements/delete.tpl:8 #: views/html/achievements/edit.tpl:8 views/html/achievements/index.tpl:16 -#: views/html/achievements/manage.tpl:8 views/html/seminarymenu/index.tpl:6 +#: views/html/achievements/manage.tpl:8 views/html/seminaries/copy.tpl:107 +#: views/html/seminarymenu/index.tpl:6 msgid "Achievements" msgstr "Achievements" @@ -432,8 +470,8 @@ msgid "Count" msgstr "Zählen" #: views/html/achievements/conditions.tpl:41 -#: views/html/achievements/conditions.tpl:108 views/html/quests/quest.tpl:116 -#: views/html/quests/quest.tpl:132 +#: views/html/achievements/conditions.tpl:108 views/html/quests/quest.tpl:120 +#: views/html/quests/quest.tpl:136 msgid "Quest" msgstr "Quest" @@ -479,7 +517,7 @@ msgid "Achievement" msgstr "Achievement" #: views/html/achievements/conditions.tpl:81 -#: views/html/achievements/delete.tpl:14 views/html/achievements/manage.tpl:24 +#: views/html/achievements/delete.tpl:14 views/html/achievements/manage.tpl:22 #: views/html/charactergroups/deletegroup.tpl:15 #: views/html/charactergroups/deletegroupsgroup.tpl:14 #: views/html/charactergroupsquests/delete.tpl:15 @@ -536,7 +574,8 @@ msgstr "Das Bild ist ungültig" #: views/html/library/edit.tpl:62 views/html/library/edit.tpl:100 #: views/html/questgroups/create.tpl:33 views/html/questgroups/edit.tpl:30 #: views/html/quests/create.tpl:30 views/html/quests/edit.tpl:30 -#: views/html/seminaries/create.tpl:30 views/html/seminaries/edit.tpl:32 +#: views/html/seminaries/copy.tpl:41 views/html/seminaries/create.tpl:30 +#: views/html/seminaries/edit.tpl:32 #, php-format msgid "Title is too short (min. %d chars)" msgstr "Der Titel ist zu kurz (min. %d Zeichen)" @@ -548,7 +587,8 @@ msgstr "Der Titel ist zu kurz (min. %d Zeichen)" #: views/html/library/edit.tpl:64 views/html/library/edit.tpl:102 #: views/html/questgroups/create.tpl:35 views/html/questgroups/edit.tpl:32 #: views/html/quests/create.tpl:32 views/html/quests/edit.tpl:32 -#: views/html/seminaries/create.tpl:32 views/html/seminaries/edit.tpl:34 +#: views/html/seminaries/copy.tpl:43 views/html/seminaries/create.tpl:32 +#: views/html/seminaries/edit.tpl:34 #, php-format msgid "Title is too long (max. %d chars)" msgstr "Der Titel ist zu lang (max. %d Zeichen)" @@ -560,7 +600,8 @@ msgstr "Der Titel ist zu lang (max. %d Zeichen)" #: views/html/library/edit.tpl:66 views/html/library/edit.tpl:104 #: views/html/questgroups/create.tpl:37 views/html/questgroups/edit.tpl:34 #: views/html/quests/create.tpl:34 views/html/quests/edit.tpl:34 -#: views/html/seminaries/create.tpl:34 views/html/seminaries/edit.tpl:36 +#: views/html/seminaries/copy.tpl:45 views/html/seminaries/create.tpl:34 +#: views/html/seminaries/edit.tpl:36 msgid "Title contains illegal characters" msgstr "Der Titel enthält ungültige Zeichen" @@ -571,7 +612,8 @@ msgstr "Der Titel enthält ungültige Zeichen" #: views/html/library/edit.tpl:68 views/html/library/edit.tpl:106 #: views/html/questgroups/create.tpl:39 views/html/questgroups/edit.tpl:36 #: views/html/quests/create.tpl:36 views/html/quests/edit.tpl:36 -#: views/html/seminaries/create.tpl:36 views/html/seminaries/edit.tpl:38 +#: views/html/seminaries/copy.tpl:47 views/html/seminaries/create.tpl:36 +#: views/html/seminaries/edit.tpl:38 msgid "Title already exists" msgstr "Der Titel existiert bereits" @@ -582,7 +624,8 @@ msgstr "Der Titel existiert bereits" #: views/html/library/edit.tpl:70 views/html/library/edit.tpl:108 #: views/html/questgroups/create.tpl:41 views/html/questgroups/edit.tpl:38 #: views/html/quests/create.tpl:38 views/html/quests/edit.tpl:38 -#: views/html/seminaries/create.tpl:38 views/html/seminaries/edit.tpl:40 +#: views/html/seminaries/copy.tpl:49 views/html/seminaries/create.tpl:38 +#: views/html/seminaries/edit.tpl:40 msgid "Title invalid" msgstr "Der Titel ist ungültig" @@ -620,9 +663,10 @@ msgstr "Erhalten" #: views/html/questgroups/questgroup.tpl:88 views/html/quests/create.tpl:70 #: views/html/quests/create.tpl:71 views/html/quests/edit.tpl:73 #: views/html/quests/edit.tpl:74 views/html/quests/index.tpl:47 -#: views/html/quests/index.tpl:48 views/html/seminaries/create.tpl:68 +#: views/html/quests/index.tpl:48 views/html/seminaries/copy.tpl:69 +#: views/html/seminaries/copy.tpl:70 views/html/seminaries/create.tpl:68 #: views/html/seminaries/create.tpl:69 views/html/seminaries/edit.tpl:70 -#: views/html/seminaries/edit.tpl:71 views/html/seminaries/seminary.tpl:65 +#: views/html/seminaries/edit.tpl:71 views/html/seminaries/seminary.tpl:68 msgid "Title" msgstr "Titel" @@ -632,6 +676,7 @@ msgstr "Titel" #: views/html/charactergroupsquests/edit.tpl:85 #: views/html/charactergroupsquests/edit.tpl:86 #: views/html/charactergroupsquests/quest.tpl:45 +#: views/html/seminaries/copy.tpl:73 views/html/seminaries/copy.tpl:74 #: views/html/seminaries/create.tpl:72 views/html/seminaries/create.tpl:73 #: views/html/seminaries/edit.tpl:74 views/html/seminaries/edit.tpl:75 msgid "Description" @@ -779,7 +824,7 @@ msgstr "erhalten am: %s" msgid "Continue playing to unlock this secret Achievement" msgstr "Spiele weiter, um diesen geheimen Erfolg freizuschalten" -#: views/html/achievements/manage.tpl:23 +#: views/html/achievements/manage.tpl:21 #: views/html/charactergroups/editgroup.tpl:83 #: views/html/charactergroups/editgroupsgroup.tpl:50 #: views/html/charactergroupsquests/edit.tpl:94 @@ -805,7 +850,8 @@ msgstr "bearbeiten" #: views/html/charactergroupsquests/edit.tpl:8 #: views/html/charactergroupsquests/manage.tpl:8 #: views/html/charactergroupsquests/quest.tpl:8 -#: views/html/characters/character.tpl:119 views/html/seminarymenu/index.tpl:5 +#: views/html/characters/character.tpl:119 views/html/seminaries/copy.tpl:109 +#: views/html/seminarymenu/index.tpl:5 msgid "Character Groups" msgstr "Gruppen" @@ -1021,7 +1067,7 @@ msgstr "%squests" #: views/html/charactergroupsquests/edit.tpl:78 #: views/html/characters/index.tpl:27 views/html/characters/index.tpl:90 #: views/html/characters/manage.tpl:17 -#: views/html/questgroups/questgroup.tpl:62 views/html/quests/create.tpl:72 +#: views/html/questgroups/questgroup.tpl:66 views/html/quests/create.tpl:72 #: views/html/quests/create.tpl:73 views/html/quests/edit.tpl:75 #: views/html/quests/edit.tpl:76 views/html/xplevels/manage.tpl:43 #: views/html/xplevels/manage.tpl:81 @@ -1056,6 +1102,7 @@ msgstr "Füge Charaktere hinzu" #: views/html/charactergroups/managegroup.tpl:59 #: views/html/questgroups/questgroup.tpl:108 views/html/quests/index.tpl:9 +#: views/html/seminaries/copy.tpl:89 msgid "Quests" msgstr "Quests" @@ -1133,6 +1180,7 @@ msgstr "%s-Quest bearbeiten" #: views/html/charactergroupsquests/manage.tpl:26 #: views/html/charactergroupsquests/quest.tpl:31 +#: views/html/seminaries/copy.tpl:81 msgid "Media" msgstr "Medien" @@ -1243,6 +1291,7 @@ msgid "The Seminary field “%s” is invalid" msgstr "Das Kursfeld „%s“ ist ungültig" #: views/html/characters/edit.tpl:86 views/html/characters/register.tpl:74 +#: views/html/seminaries/copy.tpl:79 msgid "Seminary fields" msgstr "Kursfelder" @@ -1315,7 +1364,7 @@ msgstr "Bitte wähle einen Avatar aus" #: views/html/charactertypes/create.tpl:8 #: views/html/charactertypes/delete.tpl:8 views/html/charactertypes/edit.tpl:8 -#: views/html/charactertypes/index.tpl:10 +#: views/html/charactertypes/index.tpl:10 views/html/seminaries/copy.tpl:97 msgid "Charactertypes" msgstr "Charakterrassen" @@ -1336,7 +1385,7 @@ msgstr "Soll die Charakterrasse „%s“ wirklich gelöscht werden?" msgid "Edit Charactertype" msgstr "Characterrasse bearbeiten" -#: views/html/charactertypes/edit.tpl:45 +#: views/html/charactertypes/edit.tpl:45 views/html/seminaries/copy.tpl:103 msgid "Avatars" msgstr "Avatare" @@ -1438,7 +1487,7 @@ msgstr "Einführung" #: views/html/library/create.tpl:8 views/html/library/delete.tpl:8 #: views/html/library/edit.tpl:8 views/html/library/index.tpl:9 #: views/html/library/manage.tpl:8 views/html/library/topic.tpl:8 -#: views/html/seminarymenu/index.tpl:7 +#: views/html/seminaries/copy.tpl:92 views/html/seminarymenu/index.tpl:7 msgid "Library" msgstr "Bibliothek" @@ -1506,9 +1555,9 @@ msgstr "Thema verwalten" msgid "Users" msgstr "Benutzer" -#: views/html/menu/index.tpl:3 views/html/seminaries/create.tpl:5 -#: views/html/seminaries/delete.tpl:7 views/html/seminaries/edit.tpl:7 -#: views/html/seminaries/index.tpl:4 +#: views/html/menu/index.tpl:3 views/html/seminaries/copy.tpl:7 +#: views/html/seminaries/create.tpl:5 views/html/seminaries/delete.tpl:7 +#: views/html/seminaries/edit.tpl:7 views/html/seminaries/index.tpl:4 msgid "Seminaries" msgstr "Kurse" @@ -1516,7 +1565,7 @@ msgstr "Kurse" msgid "Logout" msgstr "Logout" -#: views/html/questgroups/create.tpl:8 +#: views/html/questgroups/create.tpl:8 views/html/seminaries/copy.tpl:86 msgid "Questgroups" msgstr "Questgruppen" @@ -1525,24 +1574,28 @@ msgid "Create Questgroup" msgstr "Questgruppe erstellen" #: views/html/questgroups/create.tpl:22 views/html/questgroups/edit.tpl:19 -#: views/html/seminaries/create.tpl:19 views/html/seminaries/edit.tpl:21 +#: views/html/seminaries/copy.tpl:30 views/html/seminaries/create.tpl:19 +#: views/html/seminaries/edit.tpl:21 #, php-format msgid "Error during moodpic upload: %s" msgstr "Fehler beim Upload des Stimmungsbildes: %s" #: views/html/questgroups/create.tpl:24 views/html/questgroups/edit.tpl:21 -#: views/html/seminaries/create.tpl:21 views/html/seminaries/edit.tpl:23 +#: views/html/seminaries/copy.tpl:32 views/html/seminaries/create.tpl:21 +#: views/html/seminaries/edit.tpl:23 #, php-format msgid "Moodpic has wrong type “%s”" msgstr "Der Dateityp „%s“ ist für Stimmungsbilder nicht erlaubt" #: views/html/questgroups/create.tpl:26 views/html/questgroups/edit.tpl:23 -#: views/html/seminaries/create.tpl:23 views/html/seminaries/edit.tpl:25 +#: views/html/seminaries/copy.tpl:34 views/html/seminaries/create.tpl:23 +#: views/html/seminaries/edit.tpl:25 msgid "Moodpic exceeds size maximum" msgstr "Das Stimmungsbild ist zu groß" #: views/html/questgroups/create.tpl:28 views/html/questgroups/edit.tpl:25 -#: views/html/seminaries/create.tpl:25 views/html/seminaries/edit.tpl:27 +#: views/html/seminaries/copy.tpl:36 views/html/seminaries/create.tpl:25 +#: views/html/seminaries/edit.tpl:27 msgid "Moodpic invalid" msgstr "Das Stimmungsbild ist ungültig" @@ -1554,6 +1607,7 @@ msgstr "Einordnung" #: views/html/questgroupshierarchy/create.tpl:8 #: views/html/questgroupshierarchy/delete.tpl:8 #: views/html/questgroupshierarchy/edit.tpl:8 +#: views/html/seminaries/copy.tpl:83 msgid "Questgroupshierarchy" msgstr "Hierarchie" @@ -1591,27 +1645,27 @@ msgstr "Neue Quest erstellen" #: views/html/questgroups/questgroup.tpl:40 #: views/html/questgroupshierarchy/edit.tpl:11 -#: views/html/seminaries/seminary.tpl:24 +#: views/html/seminaries/seminary.tpl:25 msgid "Edit Questgroupshierarchy" msgstr "Hierarchie bearbeiten" #: views/html/questgroups/questgroup.tpl:41 #: views/html/questgroupshierarchy/delete.tpl:11 -#: views/html/seminaries/seminary.tpl:25 +#: views/html/seminaries/seminary.tpl:26 msgid "Delete Questgroupshierarchy" msgstr "Hierarchie löschen" -#: views/html/questgroups/questgroup.tpl:66 +#: views/html/questgroups/questgroup.tpl:70 msgid "Found optional Questline" msgstr "Optionale Questline gefunden" #: views/html/questgroups/questgroup.tpl:89 -#: views/html/seminaries/seminary.tpl:66 +#: views/html/seminaries/seminary.tpl:69 msgid "Add new Questgroup" msgstr "Neue Questgruppe hinzufügen" #: views/html/questgroups/questgroup.tpl:98 -#: views/html/seminaries/seminary.tpl:76 +#: views/html/seminaries/seminary.tpl:79 msgid "New Questgroupshierarchy" msgstr "Neue Hierarchie" @@ -1620,7 +1674,7 @@ msgstr "Neue Hierarchie" #: views/html/questgroupshierarchy/create.tpl:53 #: views/html/questgroupshierarchy/edit.tpl:52 #: views/html/questgroupshierarchy/edit.tpl:53 -#: views/html/seminaries/seminary.tpl:77 +#: views/html/seminaries/seminary.tpl:80 msgid "Title (singular)" msgstr "Titel (singular)" @@ -1629,12 +1683,12 @@ msgstr "Titel (singular)" #: views/html/questgroupshierarchy/create.tpl:55 #: views/html/questgroupshierarchy/edit.tpl:54 #: views/html/questgroupshierarchy/edit.tpl:55 -#: views/html/seminaries/seminary.tpl:78 +#: views/html/seminaries/seminary.tpl:81 msgid "Title (plural)" msgstr "Titel (plural)" #: views/html/questgroups/questgroup.tpl:102 -#: views/html/seminaries/seminary.tpl:79 +#: views/html/seminaries/seminary.tpl:82 msgid "Add new Questgroupshierarchy" msgstr "Neue Hierarchy hinzufügen" @@ -1770,26 +1824,26 @@ msgstr "Du hast die Aufgabe bereits erfolgreich gelöst" msgid "Show answer" msgstr "Lösung anzeigen" -#: views/html/quests/quest.tpl:83 +#: views/html/quests/quest.tpl:84 +msgid "Game over" +msgstr "Spielende" + +#: views/html/quests/quest.tpl:86 msgid "Epilog" msgstr "Epilog" -#: views/html/quests/quest.tpl:109 +#: views/html/quests/quest.tpl:113 msgid "Continuation" msgstr "Setze deine Reise fort" -#: views/html/quests/quest.tpl:134 +#: views/html/quests/quest.tpl:138 msgid "Go on" msgstr "Fortfahren" -#: views/html/quests/quest.tpl:143 views/html/seminaries/seminary.tpl:48 +#: views/html/quests/quest.tpl:147 views/html/seminaries/seminary.tpl:55 msgid "Let’s go" msgstr "Auf ins Abenteuer!" -#: views/html/quests/quest.tpl:146 -msgid "Game over" -msgstr "Spielende" - #: views/html/quests/submission.tpl:9 #, php-format msgid "Submission of %s" @@ -1799,25 +1853,58 @@ msgstr "Lösung von %s" msgid "Submissions" msgstr "Lösungen" -#: views/html/seminaries/create.tpl:8 -msgid "New seminary" -msgstr "Neuer Kurs" +#: views/html/seminaries/copy.tpl:10 views/html/seminaries/seminary.tpl:11 +msgid "Copy seminary" +msgstr "Kurs kopieren" -#: views/html/seminaries/create.tpl:43 views/html/seminaries/edit.tpl:45 +#: views/html/seminaries/copy.tpl:14 +#, php-format +msgid "Copying of files failed: “%s”" +msgstr "Kopieren von Dateien fehlgeschlagen: „%s“" + +#: views/html/seminaries/copy.tpl:16 +#, php-format +msgid "Copying of Seminary failed: “%s”" +msgstr "Kopieren des Kurses fehlgeschlagen: „%s“" + +#: views/html/seminaries/copy.tpl:54 views/html/seminaries/create.tpl:43 +#: views/html/seminaries/edit.tpl:45 #, php-format msgid "Course is too long (max. %d chars)" msgstr "Der Kurs ist zu lang (max. %d Zeichen)" -#: views/html/seminaries/create.tpl:45 views/html/seminaries/edit.tpl:47 +#: views/html/seminaries/copy.tpl:56 views/html/seminaries/create.tpl:45 +#: views/html/seminaries/edit.tpl:47 msgid "Course invalid" msgstr "Das Kurs ist ungültig" +#: views/html/seminaries/copy.tpl:71 views/html/seminaries/copy.tpl:72 #: views/html/seminaries/create.tpl:70 views/html/seminaries/create.tpl:71 #: views/html/seminaries/edit.tpl:72 views/html/seminaries/edit.tpl:73 msgid "Course" msgstr "Kurs" -#: views/html/seminaries/delete.tpl:10 views/html/seminaries/seminary.tpl:11 +#: views/html/seminaries/copy.tpl:77 +msgid "Elements" +msgstr "Elemente" + +#: views/html/seminaries/copy.tpl:100 +msgid "XP-Levels" +msgstr "XP-Levels" + +#: views/html/seminaries/copy.tpl:112 +msgid "Character Groups Quests" +msgstr "Gruppenquests" + +#: views/html/seminaries/copy.tpl:115 +msgid "copy" +msgstr "kopieren" + +#: views/html/seminaries/create.tpl:8 +msgid "New seminary" +msgstr "Neuer Kurs" + +#: views/html/seminaries/delete.tpl:10 views/html/seminaries/seminary.tpl:12 msgid "Delete seminary" msgstr "Kurs löschen" @@ -1848,11 +1935,11 @@ msgstr "Erstelle einen Charakter" msgid "Your Character “%s” has not been activated yet" msgstr "Dein Charakter „%s“ wurde noch nicht aktiviert" -#: views/html/seminaries/seminary.tpl:15 +#: views/html/seminaries/seminary.tpl:16 msgid "Show Quests" msgstr "Quests anzeigen" -#: views/html/seminaries/seminary.tpl:16 +#: views/html/seminaries/seminary.tpl:17 msgid "Recalculate XPs" msgstr "XP neuberechnen" @@ -2124,9 +2211,6 @@ msgstr "Hallo %s" #~ msgid "%stQuests" #~ msgstr "Quests" -#~ msgid "Character Groups Quests" -#~ msgstr "Gruppenquests" - #~ msgid "continue" #~ msgstr "fortfahren" diff --git a/models/AchievementsModel.inc b/models/AchievementsModel.inc index c5bc1006..a2d4f7c2 100644 --- a/models/AchievementsModel.inc +++ b/models/AchievementsModel.inc @@ -19,6 +19,12 @@ */ class AchievementsModel extends \hhu\z\Model { + /** + * Required models + * + * @var array + */ + public $models = array('media'); @@ -249,8 +255,9 @@ public function getAchievementsForSeminary($seminaryId) { return $this->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}