show quests on map

This commit is contained in:
Laura Klünder 2024-12-24 20:04:49 +01:00
parent 56d0925ada
commit 6acd163eb6
4 changed files with 86 additions and 5 deletions

View file

@ -10,6 +10,7 @@ from c3nav.api.auth import auth_responses
from c3nav.api.schema import BaseSchema from c3nav.api.schema import BaseSchema
from c3nav.api.utils import NonEmptyStr from c3nav.api.utils import NonEmptyStr
from c3nav.mapdata.models import MapUpdate from c3nav.mapdata.models import MapUpdate
from c3nav.mapdata.schemas.models import DataOverlaySchema
from c3nav.mapdata.utils.cache.stats import increment_cache_key from c3nav.mapdata.utils.cache.stats import increment_cache_key
from c3nav.mapdata.utils.user import get_user_data from c3nav.mapdata.utils.user import get_user_data
from c3nav.mapdata.views import set_tile_access_cookie from c3nav.mapdata.views import set_tile_access_cookie
@ -18,6 +19,7 @@ updates_api_router = APIRouter(tags=["updates"])
class UserDataSchema(BaseSchema): class UserDataSchema(BaseSchema):
# use in more places
logged_in: bool = APIField( logged_in: bool = APIField(
title="logged in", title="logged in",
description="whether a user is logged in", description="whether a user is logged in",
@ -57,6 +59,8 @@ class UserDataSchema(BaseSchema):
description="IDs of access restrictions that this user (even if maybe not signed in) has access to", description="IDs of access restrictions that this user (even if maybe not signed in) has access to",
example=[2, 5], example=[2, 5],
) )
overlays: list[DataOverlaySchema]
quests: bool
class FetchUpdatesResponseSchema(BaseSchema): class FetchUpdatesResponseSchema(BaseSchema):

View file

@ -89,7 +89,7 @@ class RangingBeaconAltitudeQuest(Quest):
@classmethod @classmethod
def _qs_for_request(cls, request): def _qs_for_request(cls, request):
return RangingBeacon.qs_for_request(request).select_related('space').filter(altitude_quest=True)[:10] return RangingBeacon.qs_for_request(request).select_related('space').filter(altitude_quest=True)
class QuestSchema(BaseSchema): class QuestSchema(BaseSchema):

View file

@ -33,14 +33,15 @@ def get_user_data(request):
if request.user.is_authenticated: if request.user.is_authenticated:
result['title'] = request.user.username result['title'] = request.user.username
# todo: cache this
result.update({ result.update({
'overlays': [ 'overlays': [
DataOverlaySchema.model_validate(overlay).model_dump() DataOverlaySchema.model_validate(overlay).model_dump()
for overlay for overlay in DataOverlay.qs_for_request(request)
in DataOverlay.qs_for_request(request) ],
] 'quests': bool(request.user.is_superuser or request.user_permissions.quests),
}) })
return result return result

View file

@ -1482,6 +1482,7 @@ c3nav = {
c3nav._routeLayerBounds = {}; c3nav._routeLayerBounds = {};
c3nav._userLocationLayers = {}; c3nav._userLocationLayers = {};
c3nav._overlayLayers = {}; c3nav._overlayLayers = {};
c3nav._questsLayers = {};
c3nav._firstRouteLevel = null; c3nav._firstRouteLevel = null;
c3nav._labelLayer = L.LayerGroup.collision({margin: 5}).addTo(c3nav.map); c3nav._labelLayer = L.LayerGroup.collision({margin: 5}).addTo(c3nav.map);
for (i = c3nav.levels.length - 1; i >= 0; i--) { for (i = c3nav.levels.length - 1; i >= 0; i--) {
@ -1492,6 +1493,7 @@ c3nav = {
c3nav._routeLayers[level[0]] = L.layerGroup().addTo(layerGroup); c3nav._routeLayers[level[0]] = L.layerGroup().addTo(layerGroup);
c3nav._userLocationLayers[level[0]] = L.layerGroup().addTo(layerGroup); c3nav._userLocationLayers[level[0]] = L.layerGroup().addTo(layerGroup);
c3nav._overlayLayers[level[0]] = L.layerGroup().addTo(layerGroup); c3nav._overlayLayers[level[0]] = L.layerGroup().addTo(layerGroup);
c3nav._questsLayers[level[0]] = L.layerGroup().addTo(layerGroup);
} }
c3nav._levelControl.finalize(); c3nav._levelControl.finalize();
c3nav._levelControl.setLevel(c3nav.initial_level); c3nav._levelControl.setLevel(c3nav.initial_level);
@ -1515,6 +1517,7 @@ c3nav = {
}).addTo(c3nav.map); }).addTo(c3nav.map);
c3nav._update_overlays(); c3nav._update_overlays();
c3nav._update_quests();
c3nav.map.on('click', c3nav._click_anywhere); c3nav.map.on('click', c3nav._click_anywhere);
@ -1892,6 +1895,7 @@ c3nav = {
c3nav_api.authenticate(); c3nav_api.authenticate();
c3nav.user_data = data; c3nav.user_data = data;
c3nav._update_overlays(); c3nav._update_overlays();
c3nav._update_quests();
var $user = $('header #user'); var $user = $('header #user');
$user.find('span').text(data.title); $user.find('span').text(data.title);
$user.find('small').text(data.subtitle || ''); $user.find('small').text(data.subtitle || '');
@ -1919,6 +1923,15 @@ c3nav = {
c3nav._overlayControl = control.addTo(c3nav.map); c3nav._overlayControl = control.addTo(c3nav.map);
} }
}, },
_update_quests: function () {
if (!c3nav.map) return;
console.log(c3nav.user_data);
if (c3nav._questsControl) {
if (!c3nav.user_data.quests) c3nav.map.removeControl(c3nav._questsControl);
} else {
if (c3nav.user_data.quests) c3nav._questsControl = (new QuestsControl()).addTo(c3nav.map);
}
},
_hasLocationPermission: undefined, _hasLocationPermission: undefined,
hasLocationPermission: function (nocache) { hasLocationPermission: function (nocache) {
@ -2438,6 +2451,69 @@ ThemeControl = L.Control.extend({
}) })
QuestsControl = L.Control.extend({
options: {
position: 'topright',
addClasses: ''
},
onAdd: function () {
this._container = L.DomUtil.create('div', 'leaflet-control-quests leaflet-bar ' + this.options.addClasses);
this._button = L.DomUtil.create('a', 'material-symbols', this._container);
$(this._button).click(this.toggleQuests).dblclick(function (e) {
e.stopPropagation();
});
this._button.innerText = c3nav._map_material_icon('editor_choice');
this._button.href = '#';
this._button.classList.toggle('control-disabled', false);
this.questsActive = false;
if (localStorageWrapper.getItem('showQuests')) {
this.showQuests();
}
return this._container;
},
toggleQuests: function (e) {
if (e) e.preventDefault();
if (c3nav._questsControl.questsActive) {
c3nav._questsControl.hideQuests();
} else {
c3nav._questsControl.showQuests();
}
},
showQuests: function () {
if (this.questsActive) return;
this._button.innerText = c3nav._map_material_icon('editor_choice');
this._button.classList.toggle('control-disabled', false);
this.questsActive = true;
localStorageWrapper.setItem('showQuests', true);
this.reloadQuests();
},
reloadQuests: function() {
c3nav_api.get('map/quests/')
.then((data) => {
for (const quest of data) {
const layer = L.geoJson(quest.point, {}).addTo(c3nav._questsLayers[quest.level_id]);
}
})
.catch();
},
hideQuests: function () {
if (!this.questsActive) return;
for (var level_id in c3nav._questsLayers) {
c3nav._questsLayers[level_id].clearLayers()
}
this._button.innerText = c3nav._map_material_icon('editor_choice');
this._button.classList.toggle('control-disabled', true);
this.questsActive = false;
localStorageWrapper.removeItem('hideQuests', true);
}
});
L.SquareGridLayer = L.Layer.extend({ L.SquareGridLayer = L.Layer.extend({
initialize: function (config) { initialize: function (config) {
this.config = config; this.config = config;