diff --git a/backend/server/adventures/views.py b/backend/server/adventures/views.py index 092b098..b1c3956 100644 --- a/backend/server/adventures/views.py +++ b/backend/server/adventures/views.py @@ -1147,9 +1147,8 @@ class ReverseGeocodeViewSet(viewsets.ViewSet): if not iso_code: return {"error": "No region found"} region = Region.objects.filter(id=iso_code).first() - visited_region = VisitedRegion.objects.filter(region=region).first() + visited_region = VisitedRegion.objects.filter(region=region, user_id=self.request.user).first() is_visited = False - print(iso_code) country_code = iso_code[:2] if region: diff --git a/backend/server/worldtravel/views.py b/backend/server/worldtravel/views.py index 8e38261..5a92e39 100644 --- a/backend/server/worldtravel/views.py +++ b/backend/server/worldtravel/views.py @@ -59,7 +59,6 @@ class CountryViewSet(viewsets.ReadOnlyModelViewSet): for adventure in adventures: if adventure.latitude is not None and adventure.longitude is not None: try: - print(f"Adventure {adventure.id}: lat={adventure.latitude}, lon={adventure.longitude}") point = Point(float(adventure.longitude), float(adventure.latitude), srid=4326) region = Region.objects.filter(geometry__contains=point).first() if region: diff --git a/documentation/.vitepress/config.mts b/documentation/.vitepress/config.mts index 5e315f8..c14b50c 100644 --- a/documentation/.vitepress/config.mts +++ b/documentation/.vitepress/config.mts @@ -65,6 +65,10 @@ export default defineConfig({ { text: "Docker 🐋", link: "/docs/install/docker" }, { text: "Proxmox LXC 🐧", link: "/docs/install/proxmox_lxc" }, { text: "Synology NAS ☁️", link: "/docs/install/synology_nas" }, + { + text: "Kubernetes and Kustomize 🌐", + link: "/docs/install/kustomize", + }, { text: "With A Reverse Proxy", @@ -113,6 +117,10 @@ export default defineConfig({ text: "Guides", collapsed: false, items: [ + { + text: "Admin Panel", + link: "/docs/guides/admin_panel", + }, { text: "v0.7.1 Migration Guide", link: "/docs/guides/v0-7-1_migration", diff --git a/documentation/docs/guides/admin_panel.md b/documentation/docs/guides/admin_panel.md new file mode 100644 index 0000000..bd13d66 --- /dev/null +++ b/documentation/docs/guides/admin_panel.md @@ -0,0 +1,11 @@ +# AdventureLog Admin Panel + +The AdventureLog Admin Panel, powered by Django, is a web-based interface that allows administrators to manage objects in the AdventureLog database. The Admin Panel is accessible at the `/admin` endpoint of the AdventureLog server. Example: `https://al-server.yourdomain.com/admin`. + +Features of the Admin Panel include: + +- **User Management**: Administrators can view and manage user accounts, including creating new users, updating user information, and deleting users. +- **Adventure Management**: Administrators can view and manage adventures, including creating new adventures, updating adventure information, and deleting adventures. +- **Security**: The Admin Panel enforces access control to ensure that only authorized administrators can access and manage the database. This means that only users with the `is_staff` flag set to `True` can access the Admin Panel. + +Note: the `CSRF_TRUSTED_ORIGINS` setting in your `docker-compose.yml` file must include the domain of the server. For example, if your server is hosted at `https://al-server.yourdomain.com`, you should add `al-server.yourdomain.com` to the `CSRF_TRUSTED_ORIGINS` setting. diff --git a/documentation/docs/install/getting_started.md b/documentation/docs/install/getting_started.md index 67d655f..d8dd5f8 100644 --- a/documentation/docs/install/getting_started.md +++ b/documentation/docs/install/getting_started.md @@ -5,6 +5,7 @@ AdventureLog can be installed in a variety of ways. The following are the most c - [Docker](docker.md) 🐳 - [Proxmox LXC](proxmox_lxc.md) 🐧 - [Synology NAS](synology_nas.md) ☁️ +- [Kubernetes and Kustomize](kustomize.md) 🌐 ### Other Options diff --git a/documentation/docs/install/kustomize.md b/documentation/docs/install/kustomize.md new file mode 100644 index 0000000..5e9d074 --- /dev/null +++ b/documentation/docs/install/kustomize.md @@ -0,0 +1,34 @@ +# Kubernetes and Kustomize (k8s) + +_AdventureLog can be run inside a kubernetes cluster using [kustomize](https://kustomize.io/)._ + +## Prerequisites + +A working kubernetes cluster. AdventureLog has been tested on k8s, but any Kustomize-capable flavor should be easy to use. + +## Cluster Routing + +Because the AdventureLog backend must be reachable by **both** the web browser and the AdventureLog frontend, k8s-internal routing mechanisms traditional for standing up other similar applications **cannot** be used. + +In order to host AdventureLog in your cluster, you must therefor configure an internally and externally resolvable ingress that routes to your AdventureLog backend container. + +Once you have made said ingress, set `PUBLIC_SERVER_URL` and `PUBLIC_URL` env variables below to the url of that ingress. + +## Tailscale and Headscale + +Many k8s homelabs choose to use [Tailscale](https://tailscale.com/) or similar projects to remove the need for open ports in your home firewall. + +The [Tailscale k8s Operator](https://tailscale.com/kb/1185/kubernetes/) will set up an externally resolvable service/ingress for your AdventureLog instance, +but it will fail to resolve internally. + +You must [expose tailnet IPs to your cluster](https://tailscale.com/kb/1438/kubernetes-operator-cluster-egress#expose-a-tailnet-https-service-to-your-cluster-workloads) so the AdventureLog pods can resolve them. + +## Getting Started + +Take a look at the [example config](https://github.com/seanmorley15/AdventureLog/blob/main/kustomization.yml) and modify it for your usecase. + +## Environment Variables + +Look at the [environment variable summary](docker.md#configuration) in the docker install section to see available and required configuration options. + +Enjoy AdventureLog! 🎉 diff --git a/documentation/pnpm-lock.yaml b/documentation/pnpm-lock.yaml index 0371b16..109ad48 100644 --- a/documentation/pnpm-lock.yaml +++ b/documentation/pnpm-lock.yaml @@ -612,8 +612,8 @@ packages: mitt@3.0.1: resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} - nanoid@3.3.7: - resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + nanoid@3.3.8: + resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -1352,7 +1352,7 @@ snapshots: mitt@3.0.1: {} - nanoid@3.3.7: {} + nanoid@3.3.8: {} oniguruma-to-es@0.4.1: dependencies: @@ -1366,7 +1366,7 @@ snapshots: postcss@8.4.49: dependencies: - nanoid: 3.3.7 + nanoid: 3.3.8 picocolors: 1.1.1 source-map-js: 1.2.1 diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 221178b..1c141b3 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -902,8 +902,8 @@ packages: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} - cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} css-selector-tokenizer@0.8.0: @@ -1440,8 +1440,8 @@ packages: mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - nanoid@3.3.7: - resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + nanoid@3.3.8: + resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -2366,7 +2366,7 @@ snapshots: '@jsdevtools/ez-spawn@3.0.4': dependencies: call-me-maybe: 1.0.2 - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 string-argv: 0.3.2 type-detect: 4.0.8 @@ -2827,7 +2827,7 @@ snapshots: cookie@0.6.0: {} - cross-spawn@7.0.3: + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 @@ -3008,7 +3008,7 @@ snapshots: execa@5.1.1: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 get-stream: 6.0.1 human-signals: 2.1.0 is-stream: 2.0.1 @@ -3065,7 +3065,7 @@ snapshots: foreground-child@3.2.1: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 signal-exit: 4.1.0 fraction.js@4.3.7: {} @@ -3404,7 +3404,7 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 - nanoid@3.3.7: {} + nanoid@3.3.8: {} next-tick@1.1.0: {} @@ -3558,13 +3558,13 @@ snapshots: postcss@8.4.38: dependencies: - nanoid: 3.3.7 + nanoid: 3.3.8 picocolors: 1.0.1 source-map-js: 1.2.0 postcss@8.4.47: dependencies: - nanoid: 3.3.7 + nanoid: 3.3.8 picocolors: 1.1.0 source-map-js: 1.2.1 diff --git a/kustomization.yml b/kustomization.yml new file mode 100644 index 0000000..da7c6e7 --- /dev/null +++ b/kustomization.yml @@ -0,0 +1,153 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: example-name + labels: + app: adventure +spec: + replicas: 1 + selector: + matchLabels: + app: adventure + template: + metadata: + name: adventure + labels: + app: adventure + spec: + volumes: + - name: adventure-journal + persistentVolumeClaim: + claimName: adventure-journal-pvc + - name: adventure-journal-db + persistentVolumeClaim: + claimName: adventure-journal-db-pvc + containers: + - name: adventure-frontend + image: ghcr.io/seanmorley15/adventurelog-frontend:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 3000 + env: + - name: PUBLIC_SERVER_URL + value: "http://internally-and-externally.reachable.io:80" + - name: ORIGIN + value: "http://url-typed-into-browser.io:80" + - name: BODY_SIZE_LIMIT + value: "Infinity" + + - name: adventure-db + image: postgis/postgis:15-3.3 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 5432 + volumeMounts: + - name: adventure-journal-db + mountPath: /var/lib/postgresql/data + env: + - name: POSTGRES_DB + value: database + - name: PGDATA + value: /var/lib/postgresql/data/pgdata/subdir + - name: POSTGRES_USER + value: adventure + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: adventurelog-secret + key: adventure-postgres-password + + - name: adventure-backend + image: ghcr.io/seanmorley15/adventurelog-backend:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 + - containerPort: 8000 + volumeMounts: + - name: adventure-journal + mountPath: /code/media + env: + - name: PGHOST + value: "adventure-db-svc" + - name: PGDATABASE + value: "database" + - name: PGUSER + value: "adventure" + - name: PGPASSWORD + valueFrom: + secretKeyRef: + name: adventurelog-secret + key: adventure-postgres-password + - name: SECRET_KEY + valueFrom: + secretKeyRef: + name: adventurelog-secret + key: adventure-postgres-password + - name: PUBLIC_URL + value: "http://internally-and-externally.reachable.io:80" # Match the outward port, used for the creation of image urls + - name: FRONTEND_URL + value: "http://url-typed-into-browser.io:80" + - name: CSRF_TRUSTED_ORIGINS + value: "http://url-typed-into-browser.io:80, http://internally-and-externally.reachable.io:80" + - name: DJANGO_ADMIN_USERNAME + value: "admin" + - name: DJANGO_ADMIN_PASSWORD + value: "admin" + - name: DJANGO_ADMIN_EMAIL + value: "admin@example.com" + - name: DEBUG + value: "True" + restartPolicy: Always +--- +apiVersion: v1 +kind: Service +metadata: + name: adventure-db-svc +spec: + selector: + app: adventure + ports: + - name: db + protocol: TCP + port: 5432 + targetPort: 5432 +--- +apiVersion: v1 +kind: Service +metadata: + name: server +spec: + selector: + app: adventure + ports: + - name: http + protocol: TCP + port: 80 + targetPort: 80 + - name: base + protocol: TCP + port: 8000 + targetPort: 8000 +--- +# If you aren't automatically provisioning PVCs (i.e. with Longhorn, you'll need to also create the PV's) +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: adventure-journal-pvc +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: adventure-journal-db-pvc +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi