├── .envrc ├── .github ├── assets │ └── banner.webp └── workflows │ ├── main.yaml │ └── pr_check.yaml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── SECURITY.md ├── backend ├── .gitignore ├── .sqlx │ ├── query-0425aa387b7928417c59e1d127448fdce052e0c081452e9fbbed8a2d252349f9.json │ ├── query-09ce979ec7e78f1e557ca00a3bf68797b369281a26682919cfbc8c447725202d.json │ ├── query-121c55cfc66bfdcadda3b6c879ec656848b554b808b614a60d3655567d7f7d48.json │ ├── query-17a7cade3e2aa93f9d6f1beddbcb164f6ab2dda148f167497edf4972e753d585.json │ ├── query-1c8aa530619f6ef63665671e7999fa2ee0a06d4d2ff0efa530600be4e1369519.json │ ├── query-1da41567d2f9913ad2e43cd889bf26a2859a2944030ca6a52917f7d3c7cf3947.json │ ├── query-214ac6fc5d8548cfd0d8fd97411ec6d943f7d6b84487f78b059535cf10f4a9a7.json │ ├── query-299e21ab01afeaa2bad80845ad860dbf9b8d963da90589a445a3b5071418a942.json │ ├── query-30141d915969c5d856ef98a52cfb29775d747273702512ff0e94c9f53b9cb6ae.json │ ├── query-3357c72b39b5cfb154ed22ed2471e12555141ffcfaefa7c068b2f4c8f73c9c64.json │ ├── query-3566e1d5ed46ca2481e39c212945686666e172577e0b4276be88e694e9947c96.json │ ├── query-3775dfc21e07361d7e0d4915fdb35c03403e04a2f1149f05ced03dbde368b1ed.json │ ├── query-3860a60a914266bf4386fe9262af2896e70f65a23683155ac0551f253ad176b9.json │ ├── query-3988d3372138cdb9d2be01bf08ec3a24517a2df8cce30b22f6ebfa45173b6cf3.json │ ├── query-39b658e5d1fd32d876be8723c09a2c3b4f4006242e24fab776191f27fcab862b.json │ ├── query-3c85c684a162418d90961456e5231bca0002f4e80da2bfcf62c4318c20be8f7f.json │ ├── query-3ec8dc8e90248fb05b43c65ed1944afe19b1248c62a022da4df181a93a11bd0b.json │ ├── query-435644c7645eb37d5c869105ddbc4172230801ba506d4aae70c84f8ea8da8d22.json │ ├── query-45761ad61a0aa459603cf56ea6e69f24cb7c02c3fece6708f6e4a220d636e9c9.json │ ├── query-47dcef54f2d7b53f35623f5747b4a2dd89b45756b33e94879c2860ea5cb5f8df.json │ ├── query-4de1c6da26f19d7f56049709bc786db9a4bc74d864a3f1184ea2ab0a4988e869.json │ ├── query-50293c2e54af11d4c2a553e29b671cef087a159c6ee7182d8ca929ecb748f3b7.json │ ├── query-50ca7413465d5fc7facfcb8598fb02e6cf93bf1d75dd33eae15052bf7ba5829b.json │ ├── query-51ea0fa88841a753ffa0b63f1771649ef335c8de49b73146e3a2831e71419b70.json │ ├── query-5316deb346a27cddcdce842ef5da51857ea95762639d548ce36918dc2027d1d2.json │ ├── query-5c948122c3a1469040cf14571318ec26a5ff98d08011d3db5d6e41377a810b41.json │ ├── query-5e6df0456cb4b90598b6f8d04bc86069d5c3558bd41481674ed50d6926d6d93e.json │ ├── query-5f5380734b3f0fa065b1830ccbacdf2ef38d24f4188b17858e79e0ff38464b69.json │ ├── query-63ca3d01283df9eae426e9ccdc3d092272f7ea3b327f5b91db9bd07343d9a651.json │ ├── query-6e6b275479ea4753c86bd3c06c4b12c65e764824fc5a82d3ebd60d17bc667233.json │ ├── query-73773148b323ae294e78a121105d0f02f74cb91cc91ad87e33880e15996e7419.json │ ├── query-774a79f460f88cbacfe0a7cd963ab3a073f83afc9eb0198fe440405e54687dc8.json │ ├── query-7b168898203679d14f1ccbcd1715ab2069b112d2df80ac40f80b3a63ee8ca92e.json │ ├── query-7f9dad2abb0f3abd4339420e1709ed1553f8dfe420760910de8a2ab6bec3073f.json │ ├── query-80d4efd69f7d05138746b053eaacf15818addf149b6c017ac8b56193d6a10245.json │ ├── query-857475123f7d8c8793f2021635520ecaa0c912138ac77009f2461a228c106c7b.json │ ├── query-8690986b3442cedfce1de17432b38892be2fdfe2daee611e8b64970772acb17b.json │ ├── query-93ea354a30d421bc27be9f28bfc99efd68d52f47025750e6663ea76ea529a3b7.json │ ├── query-9617c158d7c8cb409d9db78cfc77c783b9553ae0745c5f464dfb73557bca0f19.json │ ├── query-97070b0146d22a4b78469d02f6b842034eb8d76d219272349e7616fde7fac8ed.json │ ├── query-980dc595abe611c59bd1cc6d46dfb52a46b7fe1d830f37fdfd817121d7f1a56a.json │ ├── query-a04146ed7909d632cdd53d1df7f3f84b546863d102dd9edcc34f8655aabffb36.json │ ├── query-a2215f2b60f0171eff8a5c1f5e3c70f1ef1912a68005f77837fc0a3336e30304.json │ ├── query-a26eb8704bb81f1b60bb285994f6c79ba5f7c06c3f8fd00722f7e571727573f7.json │ ├── query-a4ad29d1517628e943a7ae118deda6fdb8dbecf42873fd2ce76c825e60fcb7ec.json │ ├── query-a4d1f12942fa45b55e31dc8f35499723e0385de509d1f81eb37cb30a2e2d73e4.json │ ├── query-a9447d27feca9fbef65a6233465c3fab45e39a4193d222338506c348e9abff56.json │ ├── query-ae38d2ce78819912784f250c1d2418bcea27807509963d6a1d3dc69a8d67df41.json │ ├── query-b0fdb9fa87e8ac1dc17e10a273355e4f20d9f920aa9fd0f7d5a216e5d4df9f2a.json │ ├── query-b3f2cc59f7f9579cb89baf7bcd5b25c8a7edf07d0b8f1782117a97fcb097d6df.json │ ├── query-b6ca4088314dfb1de406a59fd977b67123b085062e19f586a116868677338682.json │ ├── query-b96e044361f8664aef6dcf8ca00cf5d657286d7dba845a0551efc6677d40378d.json │ ├── query-c23fb52d04418585be96aca83b155e5c882d692f86a72281b2a0b2c7d9c5cefa.json │ ├── query-cb733f3d3b968f2b2e3672b6b24db324e26f5082cdcee69c35c677660a94f532.json │ ├── query-d0645eb40bf50d186b229cca83e2e4df322b902a68a86a4e82ee1fc47e031db6.json │ ├── query-d167f47a4e4b04f0616d205cd7c3e59619e9fa861a22334f27d852073f09adbf.json │ ├── query-d4667242ba0c1d645f19ad1c560d2a6cca50b06f187095053888bee95c1fd9c1.json │ ├── query-d7a7af9e4da80ce587bb5e92896616e5907f0e256342b9ffb8600c4fa27cc18d.json │ ├── query-d7fa934a55e704afce7ad68af9502dc01b5ba5a467708225c63870f6b5eeeece.json │ ├── query-d81da0cb8b8ee7f72bb84ecc104c96e274ecad13eda24e84a7aa7c856b8ca9e6.json │ ├── query-d8d142f7c2bb25eb449c391e3ca4f791f43d9188cac57b88d7839503a8e7b252.json │ ├── query-dce78dca1b1ad3816445a421c9c2888d2c68c54545d35ba851681cb32842947b.json │ ├── query-df114f7704654e85ae8a9433a91d1c4d3f603ec4992a6845c87b282bc870320e.json │ ├── query-e1c14ad1400bb468668b8e3f8d3aeccc214f090685724e76b1ec6c92be7166bd.json │ ├── query-e4bcd40211792477d6dff5d1d64d5b5b6ae3904d613c8285f750a8c6b5bd8e25.json │ ├── query-e625c5d9489f670a20dd88f3383937a290bb75a1cd229cc03e840d84a6b37ba2.json │ ├── query-e767b125954189cb00b4f7661e1f758534cf0aec5b5bc0d4c550394d449c3a4d.json │ ├── query-e92063f48832afff02878e598c3b59729ba8ff51fd774558cd26bf34e2957f1a.json │ ├── query-f611befc43dedf445e68c79972b1c4c7a02b3b0605bcf480fc99f6721891eb66.json │ ├── query-fbf5909594b8e0fc66c88fb8bf9f58fbd75eff94d127062e6d60684f8f82b8f7.json │ ├── query-fd9c4f718c8d31bf339faf83d4c5922b4f0a4a79dd6da1bc2728a93811b27e6e.json │ └── query-ffed961cdeb582dadde70c53b98dcc677c2a045ebac44669ef8a02e7a67a3a30.json ├── Cargo.lock ├── Cargo.toml ├── build.rs ├── migrations │ ├── 20240322224019_init_base_models.sql │ ├── 20240322224230_create_entities_cache.sql │ ├── 20240322224255_requests_for_entities_cache.sql │ └── 20240608185144_util_functions.sql └── src │ ├── api.rs │ ├── api │ ├── admin.rs │ ├── admin │ │ ├── access_tokens.rs │ │ ├── auth.rs │ │ ├── categories.rs │ │ ├── comments.rs │ │ ├── entities.rs │ │ ├── families.rs │ │ ├── options.rs │ │ ├── statistics.rs │ │ ├── tags.rs │ │ └── users.rs │ ├── auth.rs │ ├── icons.rs │ ├── map.rs │ └── root.rs │ ├── config.rs │ ├── doc.rs │ ├── helpers │ ├── deserializers.rs │ ├── hcaptcha.rs │ ├── mod.rs │ └── postgis_polygons.rs │ ├── main.rs │ └── models │ ├── access_token.rs │ ├── category.rs │ ├── comment.rs │ ├── entity.rs │ ├── entity_cache.rs │ ├── family.rs │ ├── icon.rs │ ├── mod.rs │ ├── options.rs │ ├── statistics.rs │ ├── tag.rs │ └── user.rs ├── container_release ├── flake.lock ├── flake.nix ├── frontend ├── .gitignore ├── app.vue ├── assets │ ├── logo_colored.svg │ ├── logo_main.svg │ ├── logo_secondary.svg │ ├── logo_square.svg │ ├── logo_square_white.svg │ ├── main.css │ └── richtext.css ├── components │ ├── AppIcon.vue │ ├── CategoryTag.vue │ ├── CommentsDisplayer.vue │ ├── DisplayedTag.vue │ ├── NominatimPicker.vue │ ├── PolygonDrawer.vue │ ├── RequiredIndicator.vue │ ├── SingleEntityMap.vue │ ├── StartPopup.vue │ ├── admin │ │ ├── EditDeleteButtons.vue │ │ ├── EntityKinshipTable.vue │ │ ├── Navbar.vue │ │ ├── Sidebar.vue │ │ ├── UserAvatar.vue │ │ ├── families │ │ │ ├── EditForm.vue │ │ │ └── EditFormJson.vue │ │ └── input │ │ │ ├── ColorField.vue │ │ │ ├── EntitySelect.vue │ │ │ ├── IconUpload.vue │ │ │ ├── NumberField.vue │ │ │ ├── PolicyPermissionField.vue │ │ │ ├── SwitchField.vue │ │ │ └── TextField.vue │ ├── form │ │ ├── Adresses.vue │ │ ├── CategorySelect.vue │ │ ├── DynamicField.vue │ │ └── TagSelect.vue │ └── viewer │ │ ├── CommentAddForm.vue │ │ ├── EntityAddForm.vue │ │ ├── FamilySwitcher.vue │ │ ├── FilterConfig.vue │ │ ├── FullResult.vue │ │ ├── Information.vue │ │ ├── Map.vue │ │ ├── Navbar.vue │ │ ├── RichTextEditor.vue │ │ ├── common │ │ ├── EntityDisplayer.vue │ │ ├── FormFields.vue │ │ └── ScoreJauge.vue │ │ └── map │ │ ├── Cluster.vue │ │ └── Marker.vue ├── composables │ └── useDarkMode.ts ├── error.vue ├── eslint.config.mjs ├── layouts │ └── admin-ui.vue ├── lib.d.ts ├── lib │ ├── admin-auth-middleware.ts │ ├── admin-client.ts │ ├── admin-state.ts │ ├── dompurify.ts │ ├── nominatim.ts │ ├── validation.ts │ ├── viewer-auth-middleware.ts │ ├── viewer-client.ts │ └── viewer-state.ts ├── nuxt.config.ts ├── openapi.json ├── package-lock.json ├── package.json ├── pages │ ├── add │ │ └── [token].vue │ ├── admin │ │ ├── [familyId] │ │ │ ├── categories │ │ │ │ ├── [id].vue │ │ │ │ ├── index.vue │ │ │ │ └── new-icon-[id].vue │ │ │ ├── comments │ │ │ │ ├── [id].vue │ │ │ │ └── pending.vue │ │ │ └── entities │ │ │ │ ├── [id].vue │ │ │ │ ├── index.vue │ │ │ │ ├── new.vue │ │ │ │ └── pending.vue │ │ ├── access-tokens │ │ │ ├── [id].vue │ │ │ ├── details │ │ │ │ └── [id].vue │ │ │ └── index.vue │ │ ├── config.vue │ │ ├── families │ │ │ ├── [id] │ │ │ │ ├── comments.vue │ │ │ │ ├── entities.vue │ │ │ │ └── general.vue │ │ │ ├── index.vue │ │ │ ├── new-icon-[id].vue │ │ │ └── new.vue │ │ ├── home.vue │ │ ├── index.vue │ │ ├── login.vue │ │ ├── tags │ │ │ ├── [id].vue │ │ │ └── index.vue │ │ └── users │ │ │ ├── [id].vue │ │ │ ├── index.vue │ │ │ └── self.vue │ ├── index.vue │ ├── map │ │ └── [token].vue │ └── search │ │ └── [token].vue ├── plugins │ ├── vue-hcaptcha.client.ts │ └── vue3-openlayers.client.ts ├── public │ └── default_favicon.ico ├── tailwind.config.js ├── theme.mjs └── tsconfig.json └── safehaven.code-workspace /.envrc: -------------------------------------------------------------------------------- 1 | use flake 2 | -------------------------------------------------------------------------------- /.github/assets/banner.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SafeHavenMaps/safehaven/ebab389d5bea0aad487169660efd6ae577c82ea4/.github/assets/banner.webp -------------------------------------------------------------------------------- /.github/workflows/pr_check.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | branches: 4 | - main 5 | 6 | jobs: 7 | build: 8 | name: Build 9 | runs-on: ubuntu-latest 10 | 11 | services: 12 | postgres: 13 | image: postgis/postgis:16-3.4-alpine 14 | env: 15 | POSTGRES_PASSWORD: postgres 16 | ports: 17 | - 5432:5432 18 | 19 | steps: 20 | - name: Checkout code 21 | uses: actions/checkout@v4 22 | 23 | - name: Install Nix 24 | uses: cachix/install-nix-action@v27 25 | 26 | - name: Run project checks 27 | run: nix develop -c check_project 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .direnv 3 | .pgdata 4 | .idea 5 | result 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
