Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@
return [
'routes' => [
['name' => 'page#index', 'url' => '/', 'verb' => 'GET'],
['name' => 'page#indexMyMap', 'url' => '/m/{myMapId}', 'verb' => 'GET'],
[
'name' => 'page#indexMyMap',
'url' => '/m/{myMapId}',
'verb' => 'GET',
'requirements' => ['myMapId' => '[0-9]+'],
],
['name' => 'page#do_echo', 'url' => '/echo', 'verb' => 'POST'],
['name' => 'page#openGeoLink', 'url' => '/openGeoLink/{url}', 'verb' => 'GET'],
['name' => 'public_favorite_page#sharedFavoritesCategory', 'url' => '/s/favorites/{token}', 'verb' => 'GET'],
Expand Down
11 changes: 8 additions & 3 deletions lib/Controller/PageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class PageController extends Controller {
public function __construct(
string $appName,
IRequest $request,
private string $userId,
private ?string $userId,
private IEventDispatcher $eventDispatcher,
IAppConfig $appConfig,
private IInitialState $initialState,
Expand Down Expand Up @@ -68,7 +68,12 @@ public function index(): TemplateResponse {
#[NoAdminRequired]
#[NoCSRFRequired]
public function indexMyMap(int $myMapId, MyMapsService $service): TemplateResponse|RedirectResponse {
$map = $service->getMyMap($myMapId, $this->userId);
$userId = $this->userId;
if ($userId === null) {
throw new \LogicException('User must be logged in');
}

$map = $service->getMyMap($myMapId, $userId);
if ($map !== null && $map['id'] !== $myMapId) {
// Instead of the id of the map containing folder the '.index.maps' file id was passed so redirect
// this happens if coming from the files app integration
Expand All @@ -80,7 +85,7 @@ public function indexMyMap(int $myMapId, MyMapsService $service): TemplateRespon
$this->eventDispatcher->dispatchTyped(new LoadSidebar());
$this->eventDispatcher->dispatchTyped(new LoadViewer());

$params = ['user' => $this->userId];
$params = ['user' => $userId];
$this->initialState->provideInitialState('photos', $this->appConfig->getValueBool('photos', 'enabled'));
$response = new TemplateResponse('maps', 'main', $params);

Expand Down
3 changes: 3 additions & 0 deletions lib/Service/MyMapsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ public function getAllMyMaps($userId): array {
public function getMyMap(int $id, string $userId): ?array {
$userFolder = $this->root->getUserFolder($userId);
$node = $userFolder->getFirstNodeById($id);
if ($node === null) {
return null;
}
if ($node instanceof Folder) {
try {
$node = $node->get('.index.maps');
Expand Down
2 changes: 2 additions & 0 deletions src/components/AppNavigationDeviceItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ export default {
},
},
emits: ['click', 'toggle-history', 'zoom', 'export', 'add-to-map-device', 'delete', 'color'],
data() {
return {
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/AppNavigationFavoritesItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@
{{ t('maps', 'Zoom to bounds') }}
</NcActionButton>
<NcActionCheckbox v-if="enabled && nbFavorites && c.enabled && c.name && c.name !== t('maps', 'Personal') && c.isShareable"
:checked="c.token && c.token !== ''"
:model-value="Boolean(c.token)"
:close-after-click="false"
@update:checked="$emit('category-share-change', catid, $event)">
@update:model-value="$emit('category-share-change', catid, $event)">
{{ c.token ? t('maps', 'Delete share link') : t('maps', 'Create share link') }}
</NcActionCheckbox>
<NcActionButton v-if="enabled && nbFavorites && c.enabled && c.token"
Expand Down
2 changes: 2 additions & 0 deletions src/components/AppNavigationMyMapItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ export default {
},
},
emits: ['click', 'rename', 'delete', 'share', 'color'],
data() {
return {
}
Expand Down
2 changes: 2 additions & 0 deletions src/components/AppNavigationMyMapsItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ export default {
},
},
emits: ['add', 'my-map-clicked', 'rename', 'delete', 'share', 'color', 'my-maps-clicked'],
data() {
return {
open: optionsController.myMapListShow,
Expand Down
4 changes: 3 additions & 1 deletion src/components/AppNavigationTrackItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@

<script>
import { NcAppNavigationItem, NcActionButton, NcActionLink } from '@nextcloud/vue'
import { isPublic, getToken } from '../utils/common'
import { isPublic, getToken } from '../utils/common.js'
import { generateUrl } from '@nextcloud/router'

export default {
Expand All @@ -103,6 +103,8 @@ export default {
},
},

emits: ['click', 'zoom', 'elevation', 'add-to-map-track', 'color'],

data() {
return {
}
Expand Down
9 changes: 5 additions & 4 deletions src/components/FavoriteEditionForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<span class="icon icon-category-organization" />
<NcSelect v-if="favorite.isUpdateable"
ref="select"
v-model="selectedCategory"
:model-value="selectedCategory"
class="category-select"
label="label"
track-by="multiselectKey"
Expand All @@ -21,12 +21,12 @@
:clear-on-select="false"
:preserve-search="false"
:placeholder="categoryPH"
inputLabel="label"
:aria-label-combobox="categoryPH"
:options="formattedCategories"
:user-select="false"
@input="onCategorySelected"
@update:model-value="onCategorySelected"
@search="onSearchChange">
<template #singleLabel="{ option }">
<template #selected-option="option">
<div class="single-label">
{{ option ? option.catid : '' }}
</div>
Expand Down Expand Up @@ -169,6 +169,7 @@ export default {
}
},
onCategorySelected(option) {
this.selectedCategory = option
this.category = option ? option.catid : ''
},
onOkClick() {
Expand Down
14 changes: 7 additions & 7 deletions src/components/MapsNavigation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,20 @@
<NcAppNavigationSettings>
<div class="maps-settings">
<NcCheckboxRadioSwitch
:checked="optionValues.trackMe === 'true'"
@update:checked="onTrackMeChange">
:model-value="optionValues.trackMe === 'true'"
@update:model-value="onTrackMeChange">
{{ window.t('maps', 'Track my position') }}
</NcCheckboxRadioSwitch>

<NcCheckboxRadioSwitch
:checked="false"
@update:checked="onGeoLinkChange">
:model-value="false"
@update:model-value="onGeoLinkChange">
{{ window.t('maps', 'Open geo links') }}
</NcCheckboxRadioSwitch>

<NcCheckboxRadioSwitch
:checked="optionValues.displaySlider === 'true'"
@update:checked="onDisplaySliderChange">
:model-value="optionValues.displaySlider === 'true'"
@update:model-value="onDisplaySliderChange">
{{ window.t('maps', 'Display time filter slider') }}
</NcCheckboxRadioSwitch>

Expand Down Expand Up @@ -158,4 +158,4 @@ export default {
z-index: 100000;
border-radius: var(--border-radius-pill);
}
</style>
</style>
4 changes: 2 additions & 2 deletions src/components/Sidebar/PhotoSuggestionsSidebarTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@
<NcAppNavigationSettings class="footer">
{{ t('maps', 'Photos default timezone:') }}
<NcTimezonePicker
:value="photoSuggestionsTimezone"
@input="$emit('change-timezone', $event)" />
:model-value="photoSuggestionsTimezone"
@update:model-value="$emit('change-timezone', $event)" />
{{ t('maps', 'Location sources:') }}
<NcAppNavigationItem
:icon="'icon-road'"
Expand Down
8 changes: 5 additions & 3 deletions src/components/map/ClickSearchPopup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@ export default {
address: null,
formattedAddress: '',
mapActions: window.OCA && window.OCA.Maps ? window.OCA.Maps.mapActions : [],
icon: L.icon({
iconUrl: 'noIcon',
icon: L.divIcon({
className: '',
html: '',
iconSize: [0, 0],
}),
}
},
Expand Down Expand Up @@ -176,4 +178,4 @@ span.icon {
width: 100%;
height: 75px;
}
</style>
</style>
20 changes: 7 additions & 13 deletions src/components/map/SearchField.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<template>
<NcSelect
ref="select"
inputLabel="label"
:aria-label-combobox="placeholder"
class="search-select"
label="label"
track-by="multiselectKey"
:value="mySelectedOption"
:model-value="mySelectedOption"
:auto-limit="false"
:limit="8"
:options-limit="8"
Expand All @@ -18,22 +18,20 @@
:options="filteredOptions"
:user-select="false"
:internal-search="false"
@input="onOptionSelected"
@update:value="onUpdateValue"
@change="onChange"
@update:model-value="onOptionSelected"
@search="onSearchChange">
<template #option="option">
<span :class="'option-icon ' + option.icon" />
<span class="option-label" :title="option.label">
{{ option.label }}
</span>
</template>
<template #singleLabel="option">
<template #selected-option="option">
<div class="single-label">
{{ option.value || option.label }}
</div>
</template>
<template #noOptions>
<template #no-options>
{{ t('maps', 'No suggestions') }}
</template>
</NcSelect>
Expand Down Expand Up @@ -145,20 +143,16 @@ export default {
}
*/
},
onOptionSelected(option, id) {
onOptionSelected(option) {
this.mySelectedOption = option
if (option?.type === 'query') {
this.searchOsm(option.value)
} else {
if (option) {
this.$emit('validate', option)
this.mySelectedOption = option
}
}
},
onUpdateValue(e) {
},
onChange(e) {
},
onSearchChange(query) {
this.query = query
this.updateCoordinateOption(query)
Expand Down
14 changes: 14 additions & 0 deletions tests/Unit/Controller/PageControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,20 @@ public function testIndex(): void {
$this->assertTrue($result instanceof TemplateResponse);
}

public function testCanBeConstructedWithoutAuthenticatedUser(): void {
$controller = new PageController(
'maps',
$this->createMock(IRequest::class),
null,
$this->eventDispatcher,
$this->appConfig,
$this->initialState,
$this->urlGenerator,
);

$this->assertInstanceOf(PageController::class, $controller);
}

public function testOpenGeoLink(): void {
$result = $this->controller->openGeoLink('geo:1.1,2.2');

Expand Down
34 changes: 34 additions & 0 deletions tests/Unit/Service/MyMapsServiceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2026 DeBaschdi
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Maps\Service;

use OCP\Files\Folder;
use OCP\Files\IRootFolder;
use PHPUnit\Framework\TestCase;

class MyMapsServiceTest extends TestCase {
public function testGetMyMapReturnsNullWhenNodeDoesNotExist(): void {
$root = $this->createMock(IRootFolder::class);
$userFolder = $this->createMock(Folder::class);

$root->expects(self::once())
->method('getUserFolder')
->with('john')
->willReturn($userFolder);
$userFolder->expects(self::once())
->method('getFirstNodeById')
->with(42)
->willReturn(null);

$service = new MyMapsService($root);

self::assertNull($service->getMyMap(42, 'john'));
}
}