Skip to content

Commit e05d378

Browse files
Merge pull request #6948 from christianbeeznest/GH-6870-6
Course: Avoid duplicated items with full restore - refs #6870
2 parents d535668 + 0b07e09 commit e05d378

File tree

3 files changed

+66
-6
lines changed

3 files changed

+66
-6
lines changed

assets/vue/components/coursemaintenance/CourseMaintenanceLayout.vue

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
:to="tabTo('CMImportBackup')"
3737
class="cm-tab"
3838
active-class="cm-tab--active"
39+
@click="goToTab('CMImportBackup', $event)"
3940
>
4041
<i class="mdi mdi-tray-arrow-down cm-tab__icon"></i>
4142
<span>{{ t("Import backup") }}</span>
@@ -46,6 +47,7 @@
4647
:to="tabTo('CMCreateBackup')"
4748
class="cm-tab"
4849
active-class="cm-tab--active"
50+
@click="goToTab('CMCreateBackup', $event)"
4951
>
5052
<i class="mdi mdi-content-save cm-tab__icon"></i>
5153
<span>{{ t("Create backup") }}</span>
@@ -56,6 +58,7 @@
5658
:to="tabTo('CMCopyCourse')"
5759
class="cm-tab"
5860
active-class="cm-tab--active"
61+
@click="goToTab('CMCopyCourse', $event)"
5962
>
6063
<i class="mdi mdi-content-copy cm-tab__icon"></i>
6164
<span>{{ t("Copy course") }}</span>
@@ -66,6 +69,7 @@
6669
:to="tabTo('CMCc13')"
6770
class="cm-tab"
6871
active-class="cm-tab--active"
72+
@click="goToTab('CMCc13', $event)"
6973
>
7074
<i class="mdi mdi-layers cm-tab__icon"></i>
7175
<span>{{ t("IMS CC 1.3") }}</span>
@@ -76,7 +80,7 @@
7680
:to="tabTo('CMRecycle')"
7781
class="cm-tab"
7882
active-class="cm-tab--active"
79-
@click.prevent="refreshRecycleTab"
83+
@click="goToTab('CMRecycle', $event)"
8084
>
8185
<i class="mdi mdi-recycle cm-tab__icon"></i>
8286
<span>{{ t("Recycle course") }}</span>
@@ -87,6 +91,7 @@
8791
:to="tabTo('CMDelete')"
8892
class="cm-tab cm-tab--danger"
8993
active-class="cm-tab--active"
94+
@click="goToTab('CMDelete', $event)"
9095
>
9196
<i class="mdi mdi-trash-can-outline cm-tab__icon"></i>
9297
<span>{{ t("Delete course") }}</span>
@@ -128,9 +133,11 @@ function tabTo(name) {
128133
}
129134
}
130135
131-
function refreshRecycleTab() {
136+
function goToTab(name, evt) {
137+
if (route.name !== name) return
138+
evt?.preventDefault?.()
132139
router.push({
133-
name: "CMRecycle",
140+
name,
134141
params: { node },
135142
query: { ...route.query, _r: Date.now().toString() },
136143
})

assets/vue/views/coursemaintenance/ImportBackup.vue

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@
6464
@change="onLocalFile"
6565
class="w-full rounded border border-gray-25 p-2 text-sm"
6666
/>
67+
<div
68+
v-if="backupType === 'local' && localFile"
69+
class="mt-1 text-tiny text-gray-50"
70+
>
71+
{{ localFile.name }}
72+
</div>
6773

6874
<!-- Server archive -->
6975
<label class="mt-4 flex items-center gap-2">
@@ -159,7 +165,7 @@
159165
<button
160166
class="btn-primary"
161167
@click="nextFromStep1"
162-
:disabled="loading"
168+
:disabled="loading || !canContinueFromStep1"
163169
>
164170
<i class="mdi mdi-arrow-right"></i> {{ t("Continue") }}
165171
</button>
@@ -243,7 +249,7 @@
243249
</template>
244250

245251
<script setup>
246-
import { ref, onMounted, watch } from "vue"
252+
import { ref, onMounted, watch, computed } from "vue"
247253
import { useRoute, useRouter } from "vue-router"
248254
import { useI18n } from "vue-i18n"
249255
import svc from "../../services/courseMaintenance"
@@ -273,6 +279,17 @@ const tree = ref([]) // groups as returned by backend
273279
const notices = ref([])
274280
const selections = ref({}) // { [type]: { [id]: 1 } }
275281
282+
const canContinueFromStep1 = computed(() => {
283+
if (backupType.value === "local") return !!localFile.value
284+
if (backupType.value === "server") return !!serverFilename.value
285+
return false
286+
})
287+
288+
watch(backupType, (v) => {
289+
if (v === "local") serverFilename.value = ""
290+
else localFile.value = null
291+
})
292+
276293
/* Lifecycle */
277294
onMounted(bootstrap)
278295
watch(

src/CourseBundle/Component/CourseCopy/CourseRestorer.php

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,6 @@ public function restore_documents($session_id = 0, $respect_base_content = false
472472
}
473473
}
474474

475-
// scan del directorio oficial de backups del archiver
476475
$scanBase = $this->getCourseBackupsBase();
477476
if (is_dir($scanBase)) {
478477
$cands = glob($scanBase.'/CourseArchiver_*', GLOB_ONLYDIR) ?: [];
@@ -785,6 +784,20 @@ public function restore_documents($session_id = 0, $respect_base_content = false
785784
$isHtml = $isHtmlFile($srcPath, $rawTitle);
786785
$rel = '/'.ltrim(substr($item->path, 8), '/'); // remove "document" prefix
787786
$parentRel = rtrim(\dirname($rel), '/');
787+
788+
if (!empty($item->destination_id) && !$isHtml) {
789+
$maybeExisting = $docRepo->find((int) $item->destination_id);
790+
if ($maybeExisting) {
791+
$this->dlog('restore_documents: already mapped asset, skipping', [
792+
'src' => $item->path ?? null,
793+
'dst_iid' => (int) $item->destination_id,
794+
]);
795+
continue;
796+
} else {
797+
$item->destination_id = 0;
798+
}
799+
}
800+
788801
$parentId = $folders[$parentRel] ?? 0;
789802
if (!$parentId) {
790803
$parentId = $ensureFolder($parentRel);
@@ -1023,6 +1036,15 @@ public function restore_forums(int $sessionId = 0): void
10231036
if (!\is_object($forumRes) || !\is_object($forumRes->obj)) {
10241037
continue;
10251038
}
1039+
1040+
if ((int) ($forumRes->destination_id ?? 0) > 0) {
1041+
$this->dlog('restore_forums: already mapped, skipping', [
1042+
'src_forum_id' => (int) $srcForumId,
1043+
'dst_forum_iid' => (int) $forumRes->destination_id,
1044+
]);
1045+
continue;
1046+
}
1047+
10261048
$p = (array) $forumRes->obj;
10271049

10281050
$dstCategory = null;
@@ -1500,6 +1522,16 @@ public function restore_links($session_id = 0): void
15001522
};
15011523

15021524
foreach ($resources[RESOURCE_LINK] as $oldLinkId => $link) {
1525+
1526+
$mapped = (int) ($this->course->resources[RESOURCE_LINK][$oldLinkId]->destination_id ?? 0);
1527+
if ($mapped > 0) {
1528+
$this->dlog('restore_links: already mapped, skipping', [
1529+
'src_link_id' => (int) $oldLinkId,
1530+
'dst_link_id' => $mapped,
1531+
]);
1532+
continue;
1533+
}
1534+
15031535
$rawUrl = (string) ($link->url ?? ($link->extra['url'] ?? ''));
15041536
$rawTitle = (string) ($link->title ?? ($link->extra['title'] ?? ''));
15051537
$rawDesc = (string) ($link->description ?? ($link->extra['description'] ?? ''));
@@ -2753,6 +2785,10 @@ public function restore_quizzes($session_id = 0, $respect_base_content = false):
27532785
}
27542786

27552787
foreach ($resources[RESOURCE_QUIZ] as $id => $quizWrap) {
2788+
if ((int) ($this->course->resources[RESOURCE_QUIZ][$id]->destination_id ?? 0) > 0) {
2789+
$this->dlog('RESTORE_QUIZ: already mapped, skipping', ['src_quiz_id' => (int) $id]);
2790+
continue;
2791+
}
27562792
$quiz = isset($quizWrap->obj) ? $quizWrap->obj : $quizWrap;
27572793

27582794
// Rewrite HTML-bearing fields

0 commit comments

Comments
 (0)