Compare commits

...

210 commits
main ... main

Author SHA1 Message Date
778a69cd 473881136a mix deps.update dataloader 2024-09-18 17:54:56 +02:00
778a69cd 317d628792 flake.lock: Update
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/c3aa7b8938b17aebd2deecf7be0636000d62a2b9' (2024-08-14)
  → 'github:NixOS/nixpkgs/99dc8785f6a0adac95f5e2ab05cc2e1bf666d172' (2024-09-16)
2024-09-18 17:22:43 +02:00
778a69cd 6df05308f6 Merge remote-tracking branch 'origin/main' 2024-09-12 23:00:29 +02:00
setop b48ab8201f feat(front): change horizontal scroll to grid view. closes #1456 2024-09-09 23:02:49 +02:00
setop 18c78b81cb feat(front): remove popular groups and online events from homepage. closes #1527 2024-09-09 16:21:17 +02:00
778a69cd 7a67cd5301 Merge remote-tracking branch 'origin/main' 2024-08-26 13:23:34 +02:00
setop 815bd8e2f9 Merge branch 'fixtests' into 'main'
Fix tests

See merge request framasoft/mobilizon!1586
2024-08-21 17:25:43 +00:00
setop 563e7be0ed test(backent): workaround test gat_actor_by_name, assertion about pictures are failing 2024-08-21 09:00:26 +02:00
setop f789fcd2ee test(backent): fix ActivityPub client mock 2024-08-20 21:59:40 +02:00
778a69cd d1a2b4acb3 nix: remove some unneeded dependencies, polishing 2024-08-19 12:29:41 +02:00
778a69cd 435cbd0d6b format all nix code by using nix fmt 2024-08-19 12:19:14 +02:00
778a69cd 656bbd46c0 build nix package by using deps_nix instead of mix2nix 2024-08-19 12:19:14 +02:00
778a69cd 375ff82076 flake.lock: Update
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/e9ee548d90ff586a6471b4ae80ae9cfcbceb3420' (2024-06-13)
  → 'github:NixOS/nixpkgs/c3aa7b8938b17aebd2deecf7be0636000d62a2b9' (2024-08-14)
2024-08-19 12:00:21 +02:00
778a69cd 191d17b42e show the browsers timezone by default, not the alleged creators timezone
Addresses potsda.mn/mobilizon#63

(cherry picked from commit 56fc90e9653b1b0f9c357022dfc85160facff0fb)
2024-08-18 14:37:35 +02:00
778a69cd da8c7b281e Merge remote-tracking branch 'origin/main' 2024-07-16 13:39:25 +02:00
setop df6ffee7cf fix(front): preserve tags when modifiying post or event
closes #1307
closes #1289
2024-07-13 08:53:24 +02:00
778a69cd 3c3206fd8a Merge remote-tracking branch 'origin/main' 2024-07-09 00:17:59 +02:00
setop 2078dbcf55 Merge branch '1475-1469-homepage-location-enhancement-no-activities' into 'main'
fix #1469 and # 1475

Closes #1469 and #1475

See merge request framasoft/mobilizon!1581
2024-07-08 21:44:23 +00:00
setop 79bd6a5d21 fix #1469 and # 1475 2024-07-08 21:44:22 +00:00
setop 0218dbe06e Merge branch '1289-updating-event-emptying-some-fields' into 'main'
Resolve "Updating an event or a groupe is emptying some fields"

Closes #1289

See merge request framasoft/mobilizon!1577
2024-07-07 15:32:35 +00:00
Massedil 93562c6be9 Resolve "Updating an event or a groupe is emptying some fields" 2024-07-07 15:32:35 +00:00
setop 4821bfc984 Merge branch 'no-single-promoted-category' into 'main'
Remove promoted categories if there is only one category

See merge request framasoft/mobilizon!1568
2024-07-06 22:34:46 +00:00
setop 8f2a8b4349 chore(front): fix linter error 2024-07-06 22:04:25 +02:00
setop 9ff494f1b5 Merge branch 'fix-calendar-beta' into 'main'
Calendar beta indication: reduce font size to make in fit on mobile

Closes #1512

See merge request framasoft/mobilizon!1569
2024-07-06 17:11:16 +00:00
setop 593f636933 Merge branch 'fix-edit-confirmation-jitter' into 'main'
Fix border width of btn-outlined-warning

See merge request framasoft/mobilizon!1580
2024-07-06 17:10:36 +00:00
setop 380031d77a Merge branch 'weblate-mobilizon-frontend' into 'main'
Translations update from Framasoft Weblate

See merge request framasoft/mobilizon!1579
2024-07-06 17:09:07 +00:00
ewm a91307116f
Translated using Weblate (Polish)
Currently translated at 99.2% (1645 of 1658 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/pl/
2024-07-06 19:07:37 +02:00
ewm aedc7a40c4
Translated using Weblate (Polish)
Currently translated at 100.0% (266 of 266 strings)

Translation: Mobilizon/Backend errors
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/backend-errors/pl/
2024-07-06 19:07:37 +02:00
ewm 04f889be4d
Translated using Weblate (Polish)
Currently translated at 99.7% (357 of 358 strings)

Translation: Mobilizon/Backend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/backend/pl/
2024-07-06 19:07:37 +02:00
ewm a3fa87a3ea
Translated using Weblate (Polish)
Currently translated at 98.1% (1627 of 1658 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/pl/
2024-07-06 19:07:37 +02:00
setop 545cb81797 Merge branch '1481-trying-to-contact-the-organizer-contact-crashes-the-app' into 'main'
trying to contact the organizer contact crashes the app

Closes #1481

See merge request framasoft/mobilizon!1565
2024-07-06 17:07:32 +00:00
setop 320c40e511 Merge branch 'main' into '1481-trying-to-contact-the-organizer-contact-crashes-the-app'
# Conflicts:
#   package.json
2024-07-06 16:21:43 +00:00
setop 46bfe5ff54 Merge branch 'translate-event-datetime-icon' into 'main'
Use the correct locale to create the event date and time icons

Closes #1515

See merge request framasoft/mobilizon!1572
2024-07-06 16:13:01 +00:00
778a69cd 8d6ee125ef Merge remote-tracking branch 'origin/main' 2024-07-05 20:51:33 +02:00
Sosthène Guédon be14c18d2e Fix border width of btn-outlined-warning 2024-07-05 15:30:36 +02:00
Sosthène Guédon 462ed5b3c7 Use the correct locale to create the event date and time icons 2024-07-05 15:10:51 +02:00
setop e51dfd392c Merge branch 'weblate-mobilizon-frontend' into 'main'
Translations update from Framasoft Weblate

See merge request framasoft/mobilizon!1566
2024-07-03 15:26:24 +00:00
Coen Holten 91f329f00a
Translated using Weblate (Dutch)
Currently translated at 92.4% (1533 of 1658 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/nl/
2024-07-03 16:36:04 +02:00
Coen Holten 7050f11ed1
Translated using Weblate (Dutch)
Currently translated at 92.4% (1532 of 1658 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/nl/
2024-07-03 16:36:04 +02:00
Coen Holten 77a6773247
Translated using Weblate (Dutch)
Currently translated at 91.3% (1515 of 1658 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/nl/
2024-07-03 16:36:04 +02:00
setop 87dd2c09cd Merge branch '1503-use-global-ssl-options-for-fetching-remote-media' into 'main'
Use RemoteMediaDownloaderClient, not Tesla directly to use global ssl options

See merge request framasoft/mobilizon!1570
2024-07-03 14:35:58 +00:00
Massedil 023f15938b @update:modelValue works again with oruga-ui 0.8.12 2024-07-01 19:55:02 +02:00
778a69cd 2f3ea848c4 Merge remote-tracking branch 'origin/main' 2024-06-30 23:29:18 +02:00
André Menrath 6d7688e4f7 Use RemoteMediaDownloaderClient, not Tesla directly to use global ssl options 2024-06-30 13:18:10 +02:00
Sosthène Guédon c6683595ff Calendar beta indication: reduce font size to make in fit on mobile 2024-06-28 23:00:00 +02:00
Sosthène Guédon c36bd4c048 Remove promoted categories if there is only one category
For instances with specific categories, this makes the category list look weird
2024-06-28 22:03:26 +02:00
setop 30d9778070 Merge branch '1503-fix-ActivityPub-publishing-for-self-signed-CA-certs' into 'main'
1503 fix ActivityPub publishing for self-signed CA certs

See merge request framasoft/mobilizon!1567
2024-06-26 11:28:31 +00:00
setop 20f62729ee Merge branch '1441-change-organizer-trigger-redirection-instanly' into 'main'
fixes #1441

Closes #1441

See merge request framasoft/mobilizon!1564
2024-06-26 10:41:11 +00:00
setop 7a7edb1b6b Merge branch '1478-my-event-show-starting-today' into 'main'
fix(frontend): my events page, handle start date correctly

Closes #1478

See merge request framasoft/mobilizon!1552
2024-06-26 10:32:58 +00:00
setop e41ecd377f fix(frontend): my events page, handle start date correctly 2024-06-26 10:32:57 +00:00
setop cde54249a9 Merge branch '1307-post-content-is-lost-when-editing' into 'main'
post data are correctly restored when editing

See merge request framasoft/mobilizon!1563
2024-06-26 09:57:06 +00:00
setop 3657636e3a tags are correctly restored on the taginput 2024-06-26 09:55:25 +00:00
Massedil d88bae8536 tags are correctly restored on the taginput 2024-06-26 09:55:25 +00:00
setop 005ef28f8c Merge branch '1443-edit-the-time-of-an-event' into 'main'
update oruga-next to 0.8.10 to solve #1443

See merge request framasoft/mobilizon!1560
2024-06-26 09:49:25 +00:00
778a69cd 7c5e8cf31f use elixir with no X dependencies, smaller nix closure 2024-06-24 15:24:09 +02:00
André Menrath b8b2e895b0 1503 fix ActivityPub publishing for self-signed CA certs 2024-06-20 22:02:31 +02:00
Massedil 745b4a82d1 remove unauthorized mediaSize in GQL FETCH_PERSON 2024-06-19 18:47:10 +02:00
Massedil c237b276ca temporarily emulate @update:modelValue 2024-06-19 17:26:27 +02:00
Massedil c0680f4bd6 type='text' is not valid for a <button> and it was triggering a form submit 2024-06-19 15:21:37 +02:00
Massedil 66280a07e6 post data are correctly restored when editing 2024-06-17 18:12:18 +02:00
778a69cd 1852d07ecf flake.lock: Update
Flake lock file updates:

• Updated input 'napalm':
    'github:nix-community/napalm/edcb26c266ca37c9521f6a97f33234633cbec186' (2023-12-20)
  → 'github:nix-community/napalm/e1babff744cd278b56abe8478008b4a9e23036cf' (2024-06-09)
• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/4cba8b53da471aea2ab2b0c1f30a81e7c451f4b6' (2024-04-08)
  → 'github:NixOS/nixpkgs/e9ee548d90ff586a6471b4ae80ae9cfcbceb3420' (2024-06-13)
2024-06-17 17:50:28 +02:00
778a69cd 3aaed0b2d7 Merge remote-tracking branch 'origin/main' 2024-06-17 17:49:53 +02:00
setop 1217f8a777 Merge branch '1457-map-tiles-dont-load' into 'main'
fix(front): don't load leaflet in the background

Closes #1457

credit to @LHolten who find the solution

See merge request framasoft/mobilizon!1562
2024-06-16 22:50:54 +00:00
setop a70bad568b fix(front): don't load leaflet in the background 2024-06-16 23:37:27 +02:00
setop 6bc2d7c970 Merge branch 'weblate-mobilizon-frontend' into 'main'
Translations update from Framasoft Weblate

See merge request framasoft/mobilizon!1555
2024-06-16 21:10:38 +00:00
Massedil 74d56aa522 update oruga-next to 0.8.10 to solve #1443 2024-06-03 18:31:39 +02:00
778a69cd ac52522992 Merge remote-tracking branch 'origin/main' 2024-05-23 17:23:41 +02:00
Coen Holten ed5fc7add6
Translated using Weblate (Dutch)
Currently translated at 91.0% (1509 of 1658 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/nl/
2024-05-15 23:37:14 +02:00
Weblate 7210869d36
Translated using Weblate (Dutch)
Currently translated at 82.4% (1367 of 1658 strings)

Co-authored-by: Coen Holten <coenholten@proton.me>
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/nl/
Translation: Mobilizon/Frontend
2024-05-15 09:52:27 +02:00
setop 5003822b09 Merge branch 'weblate-mobilizon-frontend' into 'main'
Translations update from Framasoft Weblate

See merge request framasoft/mobilizon!1554
2024-05-14 22:41:28 +00:00
Coen Holten 15c0f93e37
Translated using Weblate (Dutch)
Currently translated at 4.1% (11 of 266 strings)

Translation: Mobilizon/Backend errors
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/backend-errors/nl/
2024-05-15 00:26:17 +02:00
Coen Holten 28c045a77b
Translated using Weblate (Dutch)
Currently translated at 3.7% (10 of 266 strings)

Translation: Mobilizon/Backend errors
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/backend-errors/nl/
2024-05-15 00:00:43 +02:00
Coen Holten 442e5ae39d
Translated using Weblate (Dutch)
Currently translated at 78.0% (1294 of 1658 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/nl/
2024-05-15 00:00:42 +02:00
Coen Holten 732f4db3b9
Translated using Weblate (Dutch)
Currently translated at 75.5% (1252 of 1658 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/nl/
2024-05-14 19:47:06 +02:00
Thomas 965f72a179 Merge branch 'update-i18n' into 'main'
Translations updates

See merge request framasoft/mobilizon!1553
2024-05-14 15:43:18 +00:00
Milo Ivir 9977f3c555
Translated using Weblate (Croatian)
Currently translated at 64.2% (171 of 266 strings)

Translation: Mobilizon/Backend errors
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/backend-errors/hr/
2024-05-14 17:07:23 +02:00
Milo Ivir 5c202e31c1
Translated using Weblate (Croatian)
Currently translated at 85.4% (306 of 358 strings)

Translation: Mobilizon/Backend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/backend/hr/
2024-05-14 17:07:23 +02:00
Miguel A. Bouzada Fdz ad9bb27343
Translated using Weblate (Galician)
Currently translated at 99.9% (1657 of 1658 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/gl/
2024-05-14 17:07:23 +02:00
GSalinas ba5ac5cc94
Translated using Weblate (Spanish)
Currently translated at 100.0% (358 of 358 strings)

Translation: Mobilizon/Backend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/backend/es/
2024-05-14 17:07:23 +02:00
GSalinas dde1db73c3
Translated using Weblate (Spanish)
Currently translated at 100.0% (358 of 358 strings)

Translation: Mobilizon/Backend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/backend/es/
2024-05-14 17:07:23 +02:00
josé m b74358140c
Translated using Weblate (Galician)
Currently translated at 99.9% (1645 of 1646 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/gl/
2024-05-14 17:07:23 +02:00
josé m 49e6d8afc7
Translated using Weblate (Galician)
Currently translated at 97.4% (1604 of 1646 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/gl/
2024-05-14 17:06:59 +02:00
josé m d3fe6dece2
Translated using Weblate (Galician)
Currently translated at 91.3% (1503 of 1646 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/gl/
2024-05-14 17:06:59 +02:00
josé m 3b0d6b90ad
Translated using Weblate (Galician)
Currently translated at 82.8% (1363 of 1646 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/gl/
2024-05-14 17:06:57 +02:00
Milo Ivir 0cbe7d3d17
Translated using Weblate (Croatian)
Currently translated at 97.9% (1613 of 1646 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/hr/
2024-05-14 16:28:00 +02:00
Milo Ivir 29fb9f6934
Translated using Weblate (Croatian)
Currently translated at 93.9% (1547 of 1646 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/hr/
2024-05-14 16:27:46 +02:00
Milo Ivir dcd15f46fc
Translated using Weblate (Croatian)
Currently translated at 93.4% (1539 of 1646 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/hr/
2024-05-14 16:27:24 +02:00
Milo Ivir 7ee3c21352
Translated using Weblate (Croatian)
Currently translated at 92.4% (1522 of 1646 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/hr/
2024-05-14 16:26:44 +02:00
Milo Ivir 703256809f
Translated using Weblate (Croatian)
Currently translated at 92.4% (1522 of 1646 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/hr/
2024-05-14 16:26:43 +02:00
Milo Ivir 7491b08df2
Translated using Weblate (Croatian)
Currently translated at 92.3% (1520 of 1646 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/hr/
2024-05-14 16:25:36 +02:00
Milo Ivir 70036fefaa
Translated using Weblate (Croatian)
Currently translated at 60.5% (161 of 266 strings)

Translation: Mobilizon/Backend errors
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/backend-errors/hr/
2024-05-14 16:24:47 +02:00
Milo Ivir 014dd0d62c
Translated using Weblate (Croatian)
Currently translated at 60.1% (160 of 266 strings)

Translation: Mobilizon/Backend errors
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/backend-errors/hr/
2024-05-14 16:24:25 +02:00
Milo Ivir d651acce1f
Translated using Weblate (Croatian)
Currently translated at 90.0% (1482 of 1646 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/hr/
2024-05-14 16:23:38 +02:00
Milo Ivir f5ad8207c6
Translated using Weblate (Croatian)
Currently translated at 84.0% (301 of 358 strings)

Translation: Mobilizon/Backend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/backend/hr/
2024-05-14 16:22:51 +02:00
Milo Ivir ca95a8cab3
Translated using Weblate (Croatian)
Currently translated at 82.6% (296 of 358 strings)

Translation: Mobilizon/Backend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/backend/hr/
2024-05-14 16:22:11 +02:00
Milo Ivir 54eafe2698
Translated using Weblate (Croatian)
Currently translated at 90.0% (1482 of 1646 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/hr/
2024-05-14 16:21:33 +02:00
778a69cd 9cf861850c Merge remote-tracking branch 'origin/main' 2024-05-01 11:24:44 +02:00
setop 04ee634594 Merge branch 'madbob-main-patch-21829' into 'main'
Fix padding for homepage's search form, to align it to other elements in the same page.

See merge request framasoft/mobilizon!1550
2024-04-28 10:23:02 +00:00
setop 0a2cc39c3c Merge branch 'add-hat-geocoder-as-a-config' into 'main'
feat(backend): add hat geocoder as a config

See merge request framasoft/mobilizon!1551
2024-04-28 10:11:25 +00:00
setop a0fc154268 Merge branch 'weblate-mobilizon-frontend' into 'main'
Translations update from Framasoft Weblate

See merge request framasoft/mobilizon!1545
2024-04-28 09:53:04 +00:00
Weblate Framasoft ec616ec517 Translations update from Framasoft Weblate 2024-04-28 09:53:04 +00:00
setop d5adda00a9 feat(backend): add hat geocoder as a config 2024-04-24 12:19:44 +02:00
Roberto Guido 5998b49fae Fix padding for homepage's search form, to align it to other elements in the same page. 2024-04-21 15:12:00 +00:00
778a69cd 83dce0c8ee update mix.nix 2024-04-14 14:48:15 +02:00
778a69cd e9d17efa37 fixup bad merge on logo 2024-04-10 16:17:42 +02:00
778a69cd ad05c9ea93 flake.lock: Update
Flake lock file updates:

• Updated input 'nix-filter':
    'github:numtide/nix-filter/3449dc925982ad46246cfc36469baf66e1b64f17' (2024-01-15)
  → 'github:numtide/nix-filter/3342559a24e85fc164b295c3444e8a139924675b' (2024-03-11)
• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/faf912b086576fd1a15fca610166c98d47bc667e' (2024-02-05)
  → 'github:NixOS/nixpkgs/4cba8b53da471aea2ab2b0c1f30a81e7c451f4b6' (2024-04-08)
2024-04-10 15:43:44 +02:00
778a69cd 579397a9b5 bump version number to 5.0.0-beta.1 2024-04-10 15:40:57 +02:00
778a69cd ca76b7bcf1 Merge remote-tracking branch 'origin/main' 2024-04-10 15:33:09 +02:00
setop 162d4f5fb1 Merge branch 'v5.0-WIP' into 'main'
all developments of milestone 1

Closes #1419 and #1414

See merge request framasoft/mobilizon!1548
2024-04-10 12:36:22 +00:00
setop 7030d56864 all developments of milestone 1 2024-04-10 12:36:21 +00:00
778a69cd 5f92e4bbb9 make setting the instance_name in the Admin UI required 2024-03-08 18:12:55 +01:00
778a69cd 18f791368b neater formatting for flake.nix 2024-03-07 13:31:23 +01:00
778a69cd 6f373f5ea8 copy mobilizonConfig at setup, use writeShellApplication for better runtime checks 2024-03-07 13:31:17 +01:00
778a69cd ec4b6abc4d don't run ecto.create as we can safely assume the db already exists 2024-03-07 12:36:30 +01:00
778a69cd fa813f6216 move nixos-test to integration-test.nix 2024-03-06 00:04:54 +01:00
778a69cd 989158ef4d development environment for flake 2024-03-06 00:04:54 +01:00
778a69cd 561677ce3a mentian that we deploy from v4.x from now on 2024-03-04 12:27:27 +01:00
778a69cd 0cec96ee41 don't use a specific nodejs version but use nixpkgs default 2024-03-01 15:06:46 +01:00
778a69cd 9894330bff add comment about version number 2024-02-29 18:40:38 +01:00
778a69cd a49ba0fdbd don't preload shape-*.svg that are not rendered anymore 2024-02-29 15:09:28 +01:00
778a69cd 941d3cc3e2 fix version number in nix path so img paths work out again 2024-02-29 14:50:14 +01:00
778a69cd 864e2fa660 @apollo/client: 3.9.4 -> 3.9.5 2024-02-27 17:16:05 +01:00
778a69cd cb64baa0a4 Merge pull request 'remove fullcalendar/icalendar component as we fetch events from the GraphQl API' (#56) from remove-icalendar into main
Reviewed-on: potsda.mn/mobilizon#56
2024-02-26 11:47:49 +01:00
778a69cd 24f534fc57 remove fullcalendar/icalendar component as we fetch events from the GraphQl API 2024-02-23 19:03:16 +01:00
778a69cd 9672131ad0 Merge remote-tracking branch 'origin/main' 2024-02-19 12:07:02 +01:00
Thomas a78dc261e5 Merge branch 'fix-follow-request-email' into 'main'
fix wrong link in instance follow request text email

See merge request framasoft/mobilizon!1537
2024-02-19 08:29:33 +00:00
778a69cd de47f3da2e Revert "Fix start and end datetime picker in Event form not working"
This reverts commit f320e72991.
2024-02-17 18:29:51 +01:00
summersamara f320e72991 Fix start and end datetime picker in Event form not working
potsda.mn/mobilizon#54
2024-02-17 18:12:12 +01:00
778a69cd 7f5b792a3e actually fix wrong link in instance follow request email 2024-02-17 14:21:41 +01:00
summersamara 11fbe35725 Fix drop-down menu outside of the window: change the drop-down direction
potsda.mn/mobilizon#45
2024-02-17 14:13:00 +01:00
778a69cd a0a873d234 fix wrong link in instance follow request text email 2024-02-17 14:04:01 +01:00
778a69cd e31286040a Merge remote-tracking branch 'origin/main' 2024-02-16 15:16:43 +01:00
Thomas Citharel ddbf5a258b Merge branch 'weblate-mobilizon-frontend' into 'main'
Translations update from Framasoft Weblate

See merge request framasoft/mobilizon!1535
2024-02-12 11:57:35 +00:00
Balázs Meskó 6e23f7c55a Translated using Weblate (Hungarian)
Currently translated at 100.0% (91 of 91 strings)

Translation: Mobilizon/Activity
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/activity/hu/
2024-02-10 14:29:58 +01:00
Balázs Meskó ab0643ba3d Translated using Weblate (Hungarian)
Currently translated at 86.0% (308 of 358 strings)

Translation: Mobilizon/Backend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/backend/hu/
2024-02-10 14:29:57 +01:00
778a69cd 1fafd34fea Merge remote-tracking branch 'origin/main' 2024-02-09 20:58:09 +01:00
Ferdi Scholten 5cc4e6d0b6 Translated using Weblate (Dutch)
Currently translated at 73.8% (1216 of 1646 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/nl/
2024-02-09 18:17:08 +01:00
Thomas Citharel 831a2deb87
Release 4.1.0-alpha.1
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-09 16:10:19 +01:00
Thomas Citharel 077929318a Merge branch 'fix-tests' into 'main'
test: deactivate assert_email_sending with timeout in LegacyNotifierBuilderTest for now

Closes #1322 et #1355

See merge request framasoft/mobilizon!1534
2024-02-09 15:00:55 +00:00
Thomas Citharel f00d2babc0
chore(deps): update front-end deps
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-09 15:39:17 +01:00
Thomas Citharel f90865ffb4
refactor(deps): replace cowboy HTTP server with bandit
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-09 15:38:52 +01:00
Thomas Citharel 3f73b2f856
refactor(front): cleanup unused lines
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-09 15:24:53 +01:00
Thomas Citharel 98230a56bb
fix(front): use functions to generate classnames dynamically
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-09 15:00:45 +01:00
Thomas Citharel baa11c18b0
feat(http): allow to provide self-signed certificates
Allow for the MOBILIZON_CA_CERT_PATH to be used to provide your own root certificates. The CAStore
and certify certificates stores should be always already be used as fallback instead of the system
store.

Closes #1355

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-09 13:51:59 +01:00
Thomas Citharel 9d99684402
feat: allow to filter events by local-only
In addition to internal (self + federated) and global (global external search engine), introduce the
self possibility

Closes #1322

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-09 13:51:59 +01:00
778a69cd b31491582f Merge remote-tracking branch 'origin/main' 2024-02-09 13:41:10 +01:00
Thomas Citharel d1b1979ee5
test: deactivate assert_email_sending with timeout in LegacyNotifierBuilderTest for now
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-09 09:51:12 +01:00
Thomas Citharel 06cdb1cb43 Merge branch 'fixes' into 'main'
fix(activitypub): handle issue with AP Fetcher not catching some changeset errors

Closes #1409

See merge request framasoft/mobilizon!1531
2024-02-09 08:12:32 +00:00
Thomas Citharel 57b6bc604c Merge branch 'vite-manifest-fix' into 'main'
Provide new location for vite manifest, as that changed in vite 5

See merge request framasoft/mobilizon!1532
2024-02-09 08:11:59 +00:00
Thomas Citharel c919b992e5 Merge branch 'weblate-mobilizon-frontend' into 'main'
Translations update from Framasoft Weblate

See merge request framasoft/mobilizon!1533
2024-02-09 08:10:41 +00:00
drkfrd 445ee92f28 Translated using Weblate (Swedish)
Currently translated at 94.5% (86 of 91 strings)

Translation: Mobilizon/Activity
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/activity/sv/
2024-02-08 20:29:48 +01:00
Balázs Meskó f6435e621a Translated using Weblate (Hungarian)
Currently translated at 92.2% (1518 of 1646 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/hu/
2024-02-08 20:29:48 +01:00
778a69cd 80e3095b4c provide new location for vite manifest, as that changed in vite 5 2024-02-08 20:01:23 +01:00
778a69cd eb40d76311 provide new location for vite manifest, as that changed in vite 5 2024-02-08 19:59:43 +01:00
778a69cd 7044f63788 replace new npm patch-package call by patching npm modules in napalm 2024-02-08 19:33:57 +01:00
778a69cd 10d3d03da1 Merge remote-tracking branch 'origin/main' 2024-02-08 19:33:44 +01:00
Thomas Citharel e3b36434cb
fix(activitypub): handle issue with AP Fetcher not catching some changeset errors
Closes #1409

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:56:50 +01:00
Thomas Citharel 5429afba21 Merge branch 'fixes' into 'main'
Various fixes

Closes #1384, #1382 et #1413

See merge request framasoft/mobilizon!1523
2024-02-08 16:52:15 +00:00
Thomas Citharel 4dc2f489e7
fix(activitypub): also handle as:Public and Public values for public addressing
Closes #1413

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:52:03 +01:00
Thomas Citharel 67314928e0
test(backend): fix legacy notifier test assert
We can't refute something right after asserting it before, unfortunately

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:52:03 +01:00
Thomas Citharel 28430d6d57
feat(docker): add new environment variables for Docker config
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:52:03 +01:00
Thomas Citharel ab3f5dfd27
feat(config): enable instance feeds by default
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:52:03 +01:00
Thomas Citharel 1f4a7c253b
fix(front): patch vue-i18n-extract because of mjs incompatibility
Make sure it loads the config file in commonjs mode

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:24 +01:00
Thomas Citharel cba2075431
fix(front): correctly show error message when a tag is too short
Closes #1382

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:23 +01:00
Thomas Citharel 6a482b0d97
fix(front): various cleanups
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:23 +01:00
Thomas Citharel 34c0dd6498
fix(front): only update identity username from name if it's a new identity
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:23 +01:00
Thomas Citharel f6bcb02b98
fix(front): tagInput fixes
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:23 +01:00
Thomas Citharel b1ecf4b36f
fix(front): vite fixes after upgrade (everything is esm)
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:23 +01:00
Thomas Citharel 1acf931ac5
fix(back): sitemapper fix after upgrade
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:23 +01:00
Thomas Citharel 04edc4fef0
fix(front): husky fixes after upgrade
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:23 +01:00
Thomas Citharel 8e9f7a81b4
chore(deps): upgrade deps
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:22 +01:00
Thomas Citharel 8a2e262474
test(graphql): fix getting event conversations test
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:22 +01:00
Thomas Citharel 77308a9477
test(notifications): fix testing email notifications
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:22 +01:00
Thomas Citharel a6a1ab71c2
fix(front): various UI improvements
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:22 +01:00
Thomas Citharel 3b7124a57b
fix(front): fix focusing text editor
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:22 +01:00
Thomas Citharel ba66874cc3
fix(front): add a required attribute to the text editor and show error message if text empty on blur
Also improve text editor borders

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:22 +01:00
Thomas Citharel ef20585f8c
fix(announcements): error message not showing when an event announcement is created with empty text
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:22 +01:00
Thomas Citharel 9207d76712
chore(deps): upgrade deps
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:21 +01:00
Thomas Citharel 0bd00de501
fix(backend): only send announcement event emails when the comment author has the right to do so
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:21 +01:00
Thomas Citharel aa388a7a47
test(backend): private announcement notification jobs sends emails
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:21 +01:00
Thomas Citharel 43c6143ddf
test(graphql): having several anonymous participants for an announcement adds anonymous actor once
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:21 +01:00
Thomas Citharel 95379885c8
fix(backend): fix sending N notifications to a single conversation participant
Because of the conversation participant ID being necessary in the email, we launch N jobs to send
notifications, so we need to send the email straight away.

Anonymous participants are always only a single conversation actor
participant, so we're fine

Closes #1384

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:21 +01:00
Thomas Citharel 681f8dcd04
test(graphql): add tests for sending private event announcements
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:21 +01:00
Thomas Citharel 5bc0593ed6
fix(graphql): fix checking actor identity when publishing event announcements
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:21 +01:00
Thomas Citharel 10c4038b85
fix(backend): hide non-public replies to comments in event comment threads
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:20 +01:00
Thomas Citharel c9a1c35aa7
fix(announcements): make sure only valid announcements are shown to the user
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:20 +01:00
Thomas Citharel dcbb8eae01
feat(graphql): increase max_complexity to 300
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:20 +01:00
Thomas Citharel 6a4123f385
fix(front): fix TagInput width properly
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:20 +01:00
Thomas Citharel 01eecbf1d4
fix(event announcements): only show comments from event organizers in event announcement list
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:20 +01:00
Thomas Citharel 387d3b1c30
fix(activitypub): consider PM as private conversations even if attributed_to_id is defined
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:20 +01:00
Thomas Citharel 456dc36f64
fix(frontend): various fixes
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:20 +01:00
Thomas Citharel c12df03b5d
refactor(backend): simplify the build_begins_on function in Metadata event impl
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:19 +01:00
Thomas Citharel 5de22f91e2
fix(backend): avoid duplicating locality and region if they are the same
An example is Paris where both locality and region are named "Paris"

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:19 +01:00
Thomas Citharel 1441d35e0b
feat(activitpub): add summary of metadata to events
Currently only expressed as plain text even though it should be HTML because of Mastodon
compatibility

Ref: https://framagit.org/les/gancio/-/issues/321
Ref: https://github.com/mastodon/mastodon/issues/28455

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:19 +01:00
Thomas Citharel 594ad440da
build(credo): reactivate MissedMetadataKeyInLoggerConfig credo check after Credo 1.7.3
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:19 +01:00
Thomas Citharel 790db906a6
fix(front): fix TagInput display
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:19 +01:00
Thomas Citharel 48f57ec1cf
fix(front): reset page to lower or page 1 if we didn't found results in instances view
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:19 +01:00
Thomas Citharel 2b5439b1d0
fix(front): reset instances list to page 1 if filter or follow status changes
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:18 +01:00
Thomas Citharel 5cb4fc11c4
fix(front): rollback to vue 3.3 for now
Because of issues like https://github.com/oruga-ui/oruga/issues/709

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 17:23:18 +01:00
Thomas Citharel 410446c843 Merge branch '1399-improve-banner-image-detection' into 'main'
Improve the detection of a banner image.

Closes #1399

See merge request framasoft/mobilizon!1527
2024-02-08 16:19:06 +00:00
André Menrath 0d7462de06
Improve the detection of a banner image.
- Also accept attachments of type Image
- Prefer the key "image" if it is set as the banner image (https://www.w3.org/TR/activitystreams-vocabulary/#dfn-object)
- solves #1399

Co-authored-by: Thomas Citharel <tcit@tcit.fr>
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2024-02-08 16:55:35 +01:00
Thomas Citharel fae480c24e Merge branch 'weblate-mobilizon-frontend' into 'main'
Translations update from Framasoft Weblate

See merge request framasoft/mobilizon!1530
2024-02-08 07:49:13 +00:00
Balázs Meskó 50b1ee11a0 Translated using Weblate (Hungarian)
Currently translated at 92.3% (1518 of 1644 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/hu/
2024-02-07 23:02:50 +01:00
778a69cd ebe3e62a1e flake.lock: Update
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/97b17f32362e475016f942bbdfda4a4a72a8a652' (2024-01-29)
  → 'github:NixOS/nixpkgs/faf912b086576fd1a15fca610166c98d47bc667e' (2024-02-05)
2024-02-07 21:14:44 +01:00
778a69cd a12de7a0c1 Merge remote-tracking branch 'origin/main' 2024-02-05 14:09:02 +01:00
Thomas Citharel 54aa628403 Merge branch 'passed-events-related-backend' into 'main'
Move filtering of past events in related events section to backend

See merge request framasoft/mobilizon!1526
2024-02-05 10:21:20 +00:00
Thomas Citharel d25577ea5d Merge branch 'weblate-mobilizon-frontend' into 'main'
Translations update from Framasoft Weblate

See merge request framasoft/mobilizon!1528
2024-02-01 16:53:50 +00:00
FoW e854500693 Translated using Weblate (Korean)
Currently translated at 2.1% (36 of 1644 strings)

Translation: Mobilizon/Frontend
Translate-URL: https://weblate.framasoft.org/projects/mobilizon/frontend/ko/
2024-02-01 17:28:55 +01:00
Jonathan Reinbrecht 137a8ed69c remove unneeded import 2024-01-19 15:11:40 +01:00
Jonathan Reinbrecht 9670b77bc3 [IMP] move filtering of past events in related events section to backend 2024-01-19 13:59:01 +01:00
360 changed files with 15296 additions and 7605 deletions

View file

@ -108,9 +108,10 @@
{Credo.Check.Refactor.MatchInCondition, []},
{Credo.Check.Refactor.NegatedConditionsInUnless, []},
{Credo.Check.Refactor.NegatedConditionsWithElse, []},
{Credo.Check.Refactor.Nesting, [
max_nesting: 3
]},
{Credo.Check.Refactor.Nesting,
[
max_nesting: 3
]},
{Credo.Check.Refactor.PipeChainStart,
[
excluded_argument_types: [:atom, :binary, :fn, :keyword, :number],
@ -159,8 +160,7 @@
# Removed checks
#
{Credo.Check.Warning.LazyLogging, false},
{Credo.Check.Refactor.MapInto, false},
{Credo.Check.Warning.MissedMetadataKeyInLoggerConfig, false}
{Credo.Check.Refactor.MapInto, false}
]
}
]

View file

@ -306,7 +306,7 @@ docker-latest:
# Packaging app for amd64
package-app:
image: mobilizon/buildpack:1.15.7-erlang-26.1.2-${SYSTEM}
image: mobilizon/buildpack:1.16.1-erlang-26.2.2-${SYSTEM}
stage: build
variables: &release-variables
MIX_ENV: "prod"
@ -340,7 +340,6 @@ package-app:
"debian-buster",
"ubuntu-jammy",
"ubuntu-focal",
"ubuntu-bionic",
"fedora-38",
"fedora-39",
]

View file

@ -1,3 +1 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run pre-commit

View file

@ -1,20 +1,14 @@
155A1FB53DE39EC8EFCFD7FB94EA823D
1C29EE70E90ECED01AF28EC58D2575B5
26ED12A8E03D044BEDC08749BAA5E357
2BB1D36656B423758A470021718FCB09
31CE26BC979C57B9E3CC97B40C290CE5
3529E7A4CECC24D02678820E6F521162
3644C4E850300482AA409471EFE1EFB3
4E7C044C59E0BCB76AA826789998F624
53CBBEB6243FAF5C37249CBA17DE6F4C
5BCE3651A03711295046DE48BDFE007E
5C4CED447689F00D9D1ACEB9B895ED29
5D8350E7A2DE5BB1CBCC983AF121F0DA
94ACF7B17C3FF42F64E57DD1DA936BD8
A32E125003F1EDFAD95C487C6A969725
ACF6272A1DBB3A2ABD96C0C120B5CA69
C46C4893B2F702ACADC4CAA5683FE370
CDF2CCE0CF10F49CDFAE22FE26208155
CD4CD6571816FCAF1E305066CDA0CD2F
E720CB13C50FF3ADEE7C522531E11217
F3D5851D3FB050939841ED2F14307A27
FD1C9756370A195B74E95CE504C45E9E

View file

@ -1,2 +1,3 @@
elixir 1.15.5-otp-26
erlang 26.0.2
erlang 26.2.2
elixir 1.16.1-otp-26
nodejs 18.19.1

View file

@ -5,6 +5,184 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 4.1.0 (2024-02-29)
This release is the last provided by Framasoft. [The project is now supported by the Kaihuri association](https://framacolibri.org/t/mobilizon-nous/19752).
The highlights for this release are the following:
- improved event federation with https://event-federation.eu and https://gancio.org, as well as adding event metadata in summary for micro-blogging platforms that make use of it like Mastodon
- allowing to filter events by local-only, so that you can find only the events created on this instance
### Features
* **activitpub:** add summary of metadata to events ([1441d35](https://framagit.org/framasoft/mobilizon/commits/1441d35e0b0c3a151b8626711b3acaf30d3dcf58))
* **activitypub:** allow simple text for address field ([64237cf](https://framagit.org/framasoft/mobilizon/commits/64237cfc2633794a48022a059c79155b1ece14d1)), closes [#1387](https://framagit.org/framasoft/mobilizon/issues/1387)
* **activitypub:** implement FEP-2677 to identify the application actor used for federation ([f10977a](https://framagit.org/framasoft/mobilizon/commits/f10977a99ac73ce5a702a12ed31e773a4b0f6961)), closes [#1367](https://framagit.org/framasoft/mobilizon/issues/1367)
* allow to filter events by local-only ([9d99684](https://framagit.org/framasoft/mobilizon/commits/9d996844025f9d128305a54f8f169fb4b1ffac44)), closes [#1322](https://framagit.org/framasoft/mobilizon/issues/1322)
* **config:** enable instance feeds by default ([ab3f5df](https://framagit.org/framasoft/mobilizon/commits/ab3f5dfd278dc55dd0f28bb11cf4a976d212e9fc))
* **docker:** add new environment variables for Docker config ([28430d6](https://framagit.org/framasoft/mobilizon/commits/28430d6d57a85b568c839e75ba1bcbff90e4149e))
* **front:** upgrade to Oruga 0.8.x ([a9676d6](https://framagit.org/framasoft/mobilizon/commits/a9676d6481e6966d939ea4e44ad610eb9231c370))
* **graphql:** increase max_complexity to 300 ([dcbb8ea](https://framagit.org/framasoft/mobilizon/commits/dcbb8eae01012e6e3aa2c83e06cc50f61176b8ef))
* **http:** allow to provide self-signed certificates ([baa11c1](https://framagit.org/framasoft/mobilizon/commits/baa11c18b03684e508e56793a800878e95644962)), closes [#1355](https://framagit.org/framasoft/mobilizon/issues/1355)
* **nodeinfo:** extract and save NodeInfo information from instances to display it on instances list ([99b2339](https://framagit.org/framasoft/mobilizon/commits/99b2339424edb5b0c514581fbd6a42e4f0fcc5e1)), closes [#1392](https://framagit.org/framasoft/mobilizon/issues/1392)
### Bug Fixes
* **activitypub:** also handle as:Public and Public values for public addressing ([4dc2f48](https://framagit.org/framasoft/mobilizon/commits/4dc2f489e79d4f7d64ba3d5c2588d5d6ec0bc99c)), closes [#1413](https://framagit.org/framasoft/mobilizon/issues/1413)
* **activitypub:** consider PM as private conversations even if attributed_to_id is defined ([387d3b1](https://framagit.org/framasoft/mobilizon/commits/387d3b1c30ec719a992c565fd495ef2b6642641e))
* **activitypub:** do not try to calculate timezone from missing geo-coordinates ([001a0ed](https://framagit.org/framasoft/mobilizon/commits/001a0ed1a50894ad1abe0f7fc9dc5b9666de5dae))
* **activitypub:** handle actors following with manually_approves_followers not set ([7351468](https://framagit.org/framasoft/mobilizon/commits/73514688423b92b9f62b52fd54f2e523abeb3e34))
* **activitypub:** handle any type of error when fetching Application actor from NodeInfo ([9308c53](https://framagit.org/framasoft/mobilizon/commits/9308c5399dc2e7afd8844d083de2ea291a3c5a66))
* **activitypub:** handle issue with AP Fetcher not catching some changeset errors ([e3b3643](https://framagit.org/framasoft/mobilizon/commits/e3b36434cb05feb2e6add2b6b229e83b9dccf825)), closes [#1409](https://framagit.org/framasoft/mobilizon/issues/1409)
* **activitypub:** make relay outbox events ordered by desc publication date ([e73fd9b](https://framagit.org/framasoft/mobilizon/commits/e73fd9b370b9679a0ab424a0bd44f262a21a4697))
* **activitypub:** refresh NodeInfo metadata straight away when adding a new instance to follow ([2f4b8fe](https://framagit.org/framasoft/mobilizon/commits/2f4b8feeba9e7e1c4d1fc967505b3ed80e314b3c))
* allow html_to_text to receive nil, e.g. for empty event descriptions ([5030b75](https://framagit.org/framasoft/mobilizon/commits/5030b755a0880a022d0656598b591cb47ebd7dc5))
* **announcements:** error message not showing when an event announcement is created with empty text ([ef20585](https://framagit.org/framasoft/mobilizon/commits/ef20585f8cc1e4ac2f2f3359a70b7f456d2adeeb))
* **announcements:** make sure only valid announcements are shown to the user ([c9a1c35](https://framagit.org/framasoft/mobilizon/commits/c9a1c35aa7a1d399b524dc5cc1fbebb38681ee24))
* **backend:** avoid duplicating locality and region if they are the same ([5de22f9](https://framagit.org/framasoft/mobilizon/commits/5de22f91e22109da9e2169928dc744acd94b7299))
* **backend:** fix sending N notifications to a single conversation participant ([9537988](https://framagit.org/framasoft/mobilizon/commits/95379885c8fb3decd19fa434774023a7b05ef0b5)), closes [#1384](https://framagit.org/framasoft/mobilizon/issues/1384)
* **backend:** hide non-public replies to comments in event comment threads ([10c4038](https://framagit.org/framasoft/mobilizon/commits/10c4038b856b7e5c4981dcdce0bb9a885afb3cea))
* **backend:** only send announcement event emails when the comment author has the right to do so ([0bd00de](https://framagit.org/framasoft/mobilizon/commits/0bd00de501b36c5f2320c2530019f302bf084517))
* **backend:** validate length of instance actor details and set description column to text ([f7585cf](https://framagit.org/framasoft/mobilizon/commits/f7585cfc759576475133bcc86d2e816b2553626d)), closes [#1393](https://framagit.org/framasoft/mobilizon/issues/1393)
* **back:** fix instances filtering ([b3ba45e](https://framagit.org/framasoft/mobilizon/commits/b3ba45e8a73038dc70286afbb479c1db51b6fbcd))
* **back:** sitemapper fix after upgrade ([1acf931](https://framagit.org/framasoft/mobilizon/commits/1acf931ac558ac0818213264a6177a1f647393f1))
* **docker:** add --break-system-packages to pip install to add weasyprint and pyexcel-ods3 ([889cb91](https://framagit.org/framasoft/mobilizon/commits/889cb91f2649861a87eb7e959065cfb49b30f366))
* **docker:** remove openssl1.1-compat ([75d7816](https://framagit.org/framasoft/mobilizon/commits/75d7816a6cd1fe6754a66c1bb81153068b9c13e3)), closes [#1390](https://framagit.org/framasoft/mobilizon/issues/1390)
* **event announcements:** only show comments from event organizers in event announcement list ([01eecbf](https://framagit.org/framasoft/mobilizon/commits/01eecbf1d46614241c92e1a38e30057a84c55744))
* **feeds:** increase feed item limit from 500 to 5000 ([ff0440c](https://framagit.org/framasoft/mobilizon/commits/ff0440c634ac17813607f5929cd4024d87601c3b))
* **feeds:** make sure posts for feeds are ordered by publication date desc ([3c75856](https://framagit.org/framasoft/mobilizon/commits/3c7585614971849035011ede6c0d5d2d5621df81))
* **front-end:** fix current actor not being set on first access when relogging ([ae466b8](https://framagit.org/framasoft/mobilizon/commits/ae466b879cd09a9d04ffab0469ee991c7d90ce8e))
* **front-end:** fix issues with expired accessToken refreshment queue ([d4489f6](https://framagit.org/framasoft/mobilizon/commits/d4489f691b312891013767f7e39d92a9b0863387))
* **front:** add a required attribute to the text editor and show error message if text empty on blur ([ba66874](https://framagit.org/framasoft/mobilizon/commits/ba66874cc3e5979c2a9a6f86ea55463eca911472))
* **front:** add announcements link on EventParticipationCard as well as EventView ([83eb5c6](https://framagit.org/framasoft/mobilizon/commits/83eb5c6a69ac312c19dc3cef10f26ab686cb4be7))
* **front:** add condition on DraggableList in ResourceFolder.vue ([a408b47](https://framagit.org/framasoft/mobilizon/commits/a408b476cf2151298c7cf4eb6b3268334be13599))
* **front:** correctly show error message when a tag is too short ([cba2075](https://framagit.org/framasoft/mobilizon/commits/cba2075431d1de4bf621e1d2b2a2e5f0641997c6)), closes [#1382](https://framagit.org/framasoft/mobilizon/issues/1382)
* **front:** create head without old options ([45f8757](https://framagit.org/framasoft/mobilizon/commits/45f8757d72d1a2c72d069ced6fcbe21571d334c5))
* **frontend:** various fixes ([456dc36](https://framagit.org/framasoft/mobilizon/commits/456dc36f64b3eb7c43d8ff69aa458b89b5a5b4ab))
* **front:** escape event.title when it's passed to dialog component HTML message ([f4ee116](https://framagit.org/framasoft/mobilizon/commits/f4ee11611294c2cc957453768f768de0a51b05a7))
* **front:** fix debouncing instances filtering ([fe0cf93](https://framagit.org/framasoft/mobilizon/commits/fe0cf9360428185d261dad4065a7bea1dd8d8d59))
* **front:** fix dialog from EventParticipationCard.vue without input ([89641c5](https://framagit.org/framasoft/mobilizon/commits/89641c502ef5771f93cfa55caea6b52c63e73b4b))
* **front:** fix ErrorComponent.vue sentry integration ([00d8bc7](https://framagit.org/framasoft/mobilizon/commits/00d8bc733d52a810c438e1081496e3b0ac58958f))
* **front:** fix focus when creating a new resource ([76668e0](https://framagit.org/framasoft/mobilizon/commits/76668e0bebd2bd235925494f90fac6400e74d179))
* **front:** fix focusing text editor ([3b7124a](https://framagit.org/framasoft/mobilizon/commits/3b7124a57b2dedf5583fdebced6b9a4e502e8731))
* **front:** fix reporting group ([57d0372](https://framagit.org/framasoft/mobilizon/commits/57d0372ce8b29952caff8bbf7c902c7862a77b49))
* **front:** fix TagInput display ([790db90](https://framagit.org/framasoft/mobilizon/commits/790db906a6e814352aa694c26febb9d6a43fa321))
* **front:** fix TagInput width properly ([6a4123f](https://framagit.org/framasoft/mobilizon/commits/6a4123f385fb2e20aab1c1cbc666c5d1a3f93589))
* **front:** husky fixes after upgrade ([04edc4f](https://framagit.org/framasoft/mobilizon/commits/04edc4fef08306c55067abd0e22443c4cb43d7c8))
* **front:** improve display of SendPasswordReset view ([1d39eb5](https://framagit.org/framasoft/mobilizon/commits/1d39eb548898b3c4840b4a36950a62b4ce46ba90))
* **front:** only update identity username from name if it's a new identity ([34c0dd6](https://framagit.org/framasoft/mobilizon/commits/34c0dd6498247cf6a90576a602c4e305c80c9692))
* **front:** patch vue-i18n-extract because of mjs incompatibility ([1f4a7c2](https://framagit.org/framasoft/mobilizon/commits/1f4a7c253bfe40809b432f3a36faa6b5fb340ae9))
* **front:** remove broken identity check in EventMinimalistCard ([ee63814](https://framagit.org/framasoft/mobilizon/commits/ee6381463d9f8e6d130e29b410cf5e2700f3c10b))
* **front:** reset instances list to page 1 if filter or follow status changes ([2b5439b](https://framagit.org/framasoft/mobilizon/commits/2b5439b1d0ef1f60c19019540a01eb6d437eee23))
* **front:** reset page to lower or page 1 if we didn't found results in instances view ([48f57ec](https://framagit.org/framasoft/mobilizon/commits/48f57ec1cf3ce81c3c83333bea59c2a7d8c70e99))
* **front:** rollback to vue 3.3 for now ([5cb4fc1](https://framagit.org/framasoft/mobilizon/commits/5cb4fc11c4ccc381a041cb2615913a8fb77e1b85))
* **front:** show correct label when adding a new calc or videoconference resource in resources ([cecbea6](https://framagit.org/framasoft/mobilizon/commits/cecbea6db52d360e046d69cf0762eb1208c45f19))
* **front:** tagInput fixes ([f6bcb02](https://framagit.org/framasoft/mobilizon/commits/f6bcb02b9802e04bd8e9c80092a0680b64482688))
* **front:** uI fixes ([0948cce](https://framagit.org/framasoft/mobilizon/commits/0948cce83e5af128f78b67891ed24c323b159f0f))
* **front:** use functions to generate classnames dynamically ([98230a5](https://framagit.org/framasoft/mobilizon/commits/98230a56bb5e1c75f070e4d4c352028741869066))
* **front:** various cleanups ([6a482b0](https://framagit.org/framasoft/mobilizon/commits/6a482b0d9754fc85f1f61922e92852fbca52beb9))
* **front:** various little CSS fixes ([51d43aa](https://framagit.org/framasoft/mobilizon/commits/51d43aa2d1d1f099078895d67a45fc27b74d4604))
* **front:** various UI improvements ([a6a1ab7](https://framagit.org/framasoft/mobilizon/commits/a6a1ab71c23264805d61b5312982e6d345454027))
* **front:** vite fixes after upgrade (everything is esm) ([b1ecf4b](https://framagit.org/framasoft/mobilizon/commits/b1ecf4b36f5855c895f72c4d9dc0f7e1beb449e1))
* **graphql:** add missing operation name for RegisterPerson ([a47f4f6](https://framagit.org/framasoft/mobilizon/commits/a47f4f6444d12a13a6f7e79ed6746e74088ca294))
* **graphql:** fix checking actor identity when publishing event announcements ([5bc0593](https://framagit.org/framasoft/mobilizon/commits/5bc0593ed6e772d48722c308ccb444dc49f3c079))
* **nodeinfo:** fix getting application actor information from NodeInfo response ([dd775b6](https://framagit.org/framasoft/mobilizon/commits/dd775b6ae25f381cf76e00999fd7d37764870122))
* **nodeinfo:** make sure we only process JSON content ([da3b074](https://framagit.org/framasoft/mobilizon/commits/da3b0746198544d7977d9c0b32d8a26e1da64d40))
* **front:** fix adding tags to an event ([d75d464](https://framagit.org/framasoft/mobilizon/commits/d75d464135332f639bd275684109a89980718b75)), closes [#1419](https://framagit.org/framasoft/mobilizon/issues/1419)
* **front:** fix space around input icons ([ba9299c](https://framagit.org/framasoft/mobilizon/commits/ba9299c6321cd62bb84efb6db5b6e122e4b1b264))
* **backend:** set Gettext default locale to "en" ([d390a91](https://framagit.org/framasoft/mobilizon/commits/d390a915d80ce5d2447f5323b78c71e9e1aa58dc))
* **front:** fix discussion comment changed subscription done before having slug value ([0670297](https://framagit.org/framasoft/mobilizon/commits/067029705dd3c78b54ea4765357ba58930144aab))
* **front:** fix typing for canReport prop on DiscussionComment ([c2055d9](https://framagit.org/framasoft/mobilizon/commits/c2055d92ae7707b5aab3fd14ea827df0696cca61))
* **front:** remove extra classes on comment that are not needed ([a9b9775](https://framagit.org/framasoft/mobilizon/commits/a9b977540b900416cfe0d5739cba13e506f83120))
## 4.1.0-beta.1 (2024-02-27)
### Bug Fixes
* **front:** fix adding tags to an event ([d75d464](https://framagit.org/framasoft/mobilizon/commits/d75d464135332f639bd275684109a89980718b75)), closes [#1419](https://framagit.org/framasoft/mobilizon/issues/1419)
* **front:** fix space around input icons ([ba9299c](https://framagit.org/framasoft/mobilizon/commits/ba9299c6321cd62bb84efb6db5b6e122e4b1b264))
## 4.1.0-alpha.1 (2024-02-09)
### Features
* **activitpub:** add summary of metadata to events ([1441d35](https://framagit.org/framasoft/mobilizon/commits/1441d35e0b0c3a151b8626711b3acaf30d3dcf58))
* **activitypub:** allow simple text for address field ([64237cf](https://framagit.org/framasoft/mobilizon/commits/64237cfc2633794a48022a059c79155b1ece14d1)), closes [#1387](https://framagit.org/framasoft/mobilizon/issues/1387)
* **activitypub:** implement FEP-2677 to identify the application actor used for federation ([f10977a](https://framagit.org/framasoft/mobilizon/commits/f10977a99ac73ce5a702a12ed31e773a4b0f6961)), closes [#1367](https://framagit.org/framasoft/mobilizon/issues/1367)
* allow to filter events by local-only ([9d99684](https://framagit.org/framasoft/mobilizon/commits/9d996844025f9d128305a54f8f169fb4b1ffac44)), closes [#1322](https://framagit.org/framasoft/mobilizon/issues/1322)
* **config:** enable instance feeds by default ([ab3f5df](https://framagit.org/framasoft/mobilizon/commits/ab3f5dfd278dc55dd0f28bb11cf4a976d212e9fc))
* **docker:** add new environment variables for Docker config ([28430d6](https://framagit.org/framasoft/mobilizon/commits/28430d6d57a85b568c839e75ba1bcbff90e4149e))
* **front:** upgrade to Oruga 0.8.x ([a9676d6](https://framagit.org/framasoft/mobilizon/commits/a9676d6481e6966d939ea4e44ad610eb9231c370))
* **graphql:** increase max_complexity to 300 ([dcbb8ea](https://framagit.org/framasoft/mobilizon/commits/dcbb8eae01012e6e3aa2c83e06cc50f61176b8ef))
* **http:** allow to provide self-signed certificates ([baa11c1](https://framagit.org/framasoft/mobilizon/commits/baa11c18b03684e508e56793a800878e95644962)), closes [#1355](https://framagit.org/framasoft/mobilizon/issues/1355)
* **nodeinfo:** extract and save NodeInfo information from instances to display it on instances list ([99b2339](https://framagit.org/framasoft/mobilizon/commits/99b2339424edb5b0c514581fbd6a42e4f0fcc5e1)), closes [#1392](https://framagit.org/framasoft/mobilizon/issues/1392)
### Bug Fixes
* **activitypub:** also handle as:Public and Public values for public addressing ([4dc2f48](https://framagit.org/framasoft/mobilizon/commits/4dc2f489e79d4f7d64ba3d5c2588d5d6ec0bc99c)), closes [#1413](https://framagit.org/framasoft/mobilizon/issues/1413)
* **activitypub:** consider PM as private conversations even if attributed_to_id is defined ([387d3b1](https://framagit.org/framasoft/mobilizon/commits/387d3b1c30ec719a992c565fd495ef2b6642641e))
* **activitypub:** do not try to calculate timezone from missing geo-coordinates ([001a0ed](https://framagit.org/framasoft/mobilizon/commits/001a0ed1a50894ad1abe0f7fc9dc5b9666de5dae))
* **activitypub:** handle actors following with manually_approves_followers not set ([7351468](https://framagit.org/framasoft/mobilizon/commits/73514688423b92b9f62b52fd54f2e523abeb3e34))
* **activitypub:** handle any type of error when fetching Application actor from NodeInfo ([9308c53](https://framagit.org/framasoft/mobilizon/commits/9308c5399dc2e7afd8844d083de2ea291a3c5a66))
* **activitypub:** handle issue with AP Fetcher not catching some changeset errors ([e3b3643](https://framagit.org/framasoft/mobilizon/commits/e3b36434cb05feb2e6add2b6b229e83b9dccf825)), closes [#1409](https://framagit.org/framasoft/mobilizon/issues/1409)
* **activitypub:** make relay outbox events ordered by desc publication date ([e73fd9b](https://framagit.org/framasoft/mobilizon/commits/e73fd9b370b9679a0ab424a0bd44f262a21a4697))
* **activitypub:** refresh NodeInfo metadata straight away when adding a new instance to follow ([2f4b8fe](https://framagit.org/framasoft/mobilizon/commits/2f4b8feeba9e7e1c4d1fc967505b3ed80e314b3c))
* allow html_to_text to receive nil, e.g. for empty event descriptions ([5030b75](https://framagit.org/framasoft/mobilizon/commits/5030b755a0880a022d0656598b591cb47ebd7dc5))
* **announcements:** error message not showing when an event announcement is created with empty text ([ef20585](https://framagit.org/framasoft/mobilizon/commits/ef20585f8cc1e4ac2f2f3359a70b7f456d2adeeb))
* **announcements:** make sure only valid announcements are shown to the user ([c9a1c35](https://framagit.org/framasoft/mobilizon/commits/c9a1c35aa7a1d399b524dc5cc1fbebb38681ee24))
* **backend:** avoid duplicating locality and region if they are the same ([5de22f9](https://framagit.org/framasoft/mobilizon/commits/5de22f91e22109da9e2169928dc744acd94b7299))
* **backend:** fix sending N notifications to a single conversation participant ([9537988](https://framagit.org/framasoft/mobilizon/commits/95379885c8fb3decd19fa434774023a7b05ef0b5)), closes [#1384](https://framagit.org/framasoft/mobilizon/issues/1384)
* **backend:** hide non-public replies to comments in event comment threads ([10c4038](https://framagit.org/framasoft/mobilizon/commits/10c4038b856b7e5c4981dcdce0bb9a885afb3cea))
* **backend:** only send announcement event emails when the comment author has the right to do so ([0bd00de](https://framagit.org/framasoft/mobilizon/commits/0bd00de501b36c5f2320c2530019f302bf084517))
* **backend:** validate length of instance actor details and set description column to text ([f7585cf](https://framagit.org/framasoft/mobilizon/commits/f7585cfc759576475133bcc86d2e816b2553626d)), closes [#1393](https://framagit.org/framasoft/mobilizon/issues/1393)
* **back:** fix instances filtering ([b3ba45e](https://framagit.org/framasoft/mobilizon/commits/b3ba45e8a73038dc70286afbb479c1db51b6fbcd))
* **back:** sitemapper fix after upgrade ([1acf931](https://framagit.org/framasoft/mobilizon/commits/1acf931ac558ac0818213264a6177a1f647393f1))
* **docker:** add --break-system-packages to pip install to add weasyprint and pyexcel-ods3 ([889cb91](https://framagit.org/framasoft/mobilizon/commits/889cb91f2649861a87eb7e959065cfb49b30f366))
* **docker:** remove openssl1.1-compat ([75d7816](https://framagit.org/framasoft/mobilizon/commits/75d7816a6cd1fe6754a66c1bb81153068b9c13e3)), closes [#1390](https://framagit.org/framasoft/mobilizon/issues/1390)
* **event announcements:** only show comments from event organizers in event announcement list ([01eecbf](https://framagit.org/framasoft/mobilizon/commits/01eecbf1d46614241c92e1a38e30057a84c55744))
* **feeds:** increase feed item limit from 500 to 5000 ([ff0440c](https://framagit.org/framasoft/mobilizon/commits/ff0440c634ac17813607f5929cd4024d87601c3b))
* **feeds:** make sure posts for feeds are ordered by publication date desc ([3c75856](https://framagit.org/framasoft/mobilizon/commits/3c7585614971849035011ede6c0d5d2d5621df81))
* **front-end:** fix current actor not being set on first access when relogging ([ae466b8](https://framagit.org/framasoft/mobilizon/commits/ae466b879cd09a9d04ffab0469ee991c7d90ce8e))
* **front-end:** fix issues with expired accessToken refreshment queue ([d4489f6](https://framagit.org/framasoft/mobilizon/commits/d4489f691b312891013767f7e39d92a9b0863387))
* **front:** add a required attribute to the text editor and show error message if text empty on blur ([ba66874](https://framagit.org/framasoft/mobilizon/commits/ba66874cc3e5979c2a9a6f86ea55463eca911472))
* **front:** add announcements link on EventParticipationCard as well as EventView ([83eb5c6](https://framagit.org/framasoft/mobilizon/commits/83eb5c6a69ac312c19dc3cef10f26ab686cb4be7))
* **front:** add condition on DraggableList in ResourceFolder.vue ([a408b47](https://framagit.org/framasoft/mobilizon/commits/a408b476cf2151298c7cf4eb6b3268334be13599))
* **front:** correctly show error message when a tag is too short ([cba2075](https://framagit.org/framasoft/mobilizon/commits/cba2075431d1de4bf621e1d2b2a2e5f0641997c6)), closes [#1382](https://framagit.org/framasoft/mobilizon/issues/1382)
* **front:** create head without old options ([45f8757](https://framagit.org/framasoft/mobilizon/commits/45f8757d72d1a2c72d069ced6fcbe21571d334c5))
* **frontend:** various fixes ([456dc36](https://framagit.org/framasoft/mobilizon/commits/456dc36f64b3eb7c43d8ff69aa458b89b5a5b4ab))
* **front:** escape event.title when it's passed to dialog component HTML message ([f4ee116](https://framagit.org/framasoft/mobilizon/commits/f4ee11611294c2cc957453768f768de0a51b05a7))
* **front:** fix debouncing instances filtering ([fe0cf93](https://framagit.org/framasoft/mobilizon/commits/fe0cf9360428185d261dad4065a7bea1dd8d8d59))
* **front:** fix dialog from EventParticipationCard.vue without input ([89641c5](https://framagit.org/framasoft/mobilizon/commits/89641c502ef5771f93cfa55caea6b52c63e73b4b))
* **front:** fix ErrorComponent.vue sentry integration ([00d8bc7](https://framagit.org/framasoft/mobilizon/commits/00d8bc733d52a810c438e1081496e3b0ac58958f))
* **front:** fix focus when creating a new resource ([76668e0](https://framagit.org/framasoft/mobilizon/commits/76668e0bebd2bd235925494f90fac6400e74d179))
* **front:** fix focusing text editor ([3b7124a](https://framagit.org/framasoft/mobilizon/commits/3b7124a57b2dedf5583fdebced6b9a4e502e8731))
* **front:** fix reporting group ([57d0372](https://framagit.org/framasoft/mobilizon/commits/57d0372ce8b29952caff8bbf7c902c7862a77b49))
* **front:** fix TagInput display ([790db90](https://framagit.org/framasoft/mobilizon/commits/790db906a6e814352aa694c26febb9d6a43fa321))
* **front:** fix TagInput width properly ([6a4123f](https://framagit.org/framasoft/mobilizon/commits/6a4123f385fb2e20aab1c1cbc666c5d1a3f93589))
* **front:** husky fixes after upgrade ([04edc4f](https://framagit.org/framasoft/mobilizon/commits/04edc4fef08306c55067abd0e22443c4cb43d7c8))
* **front:** improve display of SendPasswordReset view ([1d39eb5](https://framagit.org/framasoft/mobilizon/commits/1d39eb548898b3c4840b4a36950a62b4ce46ba90))
* **front:** only update identity username from name if it's a new identity ([34c0dd6](https://framagit.org/framasoft/mobilizon/commits/34c0dd6498247cf6a90576a602c4e305c80c9692))
* **front:** patch vue-i18n-extract because of mjs incompatibility ([1f4a7c2](https://framagit.org/framasoft/mobilizon/commits/1f4a7c253bfe40809b432f3a36faa6b5fb340ae9))
* **front:** remove broken identity check in EventMinimalistCard ([ee63814](https://framagit.org/framasoft/mobilizon/commits/ee6381463d9f8e6d130e29b410cf5e2700f3c10b))
* **front:** reset instances list to page 1 if filter or follow status changes ([2b5439b](https://framagit.org/framasoft/mobilizon/commits/2b5439b1d0ef1f60c19019540a01eb6d437eee23))
* **front:** reset page to lower or page 1 if we didn't found results in instances view ([48f57ec](https://framagit.org/framasoft/mobilizon/commits/48f57ec1cf3ce81c3c83333bea59c2a7d8c70e99))
* **front:** rollback to vue 3.3 for now ([5cb4fc1](https://framagit.org/framasoft/mobilizon/commits/5cb4fc11c4ccc381a041cb2615913a8fb77e1b85))
* **front:** show correct label when adding a new calc or videoconference resource in resources ([cecbea6](https://framagit.org/framasoft/mobilizon/commits/cecbea6db52d360e046d69cf0762eb1208c45f19))
* **front:** tagInput fixes ([f6bcb02](https://framagit.org/framasoft/mobilizon/commits/f6bcb02b9802e04bd8e9c80092a0680b64482688))
* **front:** uI fixes ([0948cce](https://framagit.org/framasoft/mobilizon/commits/0948cce83e5af128f78b67891ed24c323b159f0f))
* **front:** use functions to generate classnames dynamically ([98230a5](https://framagit.org/framasoft/mobilizon/commits/98230a56bb5e1c75f070e4d4c352028741869066))
* **front:** various cleanups ([6a482b0](https://framagit.org/framasoft/mobilizon/commits/6a482b0d9754fc85f1f61922e92852fbca52beb9))
* **front:** various little CSS fixes ([51d43aa](https://framagit.org/framasoft/mobilizon/commits/51d43aa2d1d1f099078895d67a45fc27b74d4604))
* **front:** various UI improvements ([a6a1ab7](https://framagit.org/framasoft/mobilizon/commits/a6a1ab71c23264805d61b5312982e6d345454027))
* **front:** vite fixes after upgrade (everything is esm) ([b1ecf4b](https://framagit.org/framasoft/mobilizon/commits/b1ecf4b36f5855c895f72c4d9dc0f7e1beb449e1))
* **graphql:** add missing operation name for RegisterPerson ([a47f4f6](https://framagit.org/framasoft/mobilizon/commits/a47f4f6444d12a13a6f7e79ed6746e74088ca294))
* **graphql:** fix checking actor identity when publishing event announcements ([5bc0593](https://framagit.org/framasoft/mobilizon/commits/5bc0593ed6e772d48722c308ccb444dc49f3c079))
* **nodeinfo:** fix getting application actor information from NodeInfo response ([dd775b6](https://framagit.org/framasoft/mobilizon/commits/dd775b6ae25f381cf76e00999fd7d37764870122))
* **nodeinfo:** make sure we only process JSON content ([da3b074](https://framagit.org/framasoft/mobilizon/commits/da3b0746198544d7977d9c0b32d8a26e1da64d40))
## 4.0.2 (2023-12-07)
### Security issues

View file

@ -630,7 +630,7 @@ state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Mobilizon
Copyright (C) 2018 Thomas Citharel
Copyright (C) 2018 - 2024 Framasoft
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published

View file

@ -19,8 +19,8 @@ stop:
@bash docker/message.sh "Mobilizon is stopped"
test: stop
@bash docker/message.sh "Running tests"
docker compose -f docker compose.yml -f docker compose.test.yml run api mix prepare_test
docker compose -f docker compose.yml -f docker compose.test.yml run api mix test $(only)
docker compose -f docker-compose.yml -f docker-compose.test.yml run api mix prepare_test
docker compose -f docker-compose.yml -f docker-compose.test.yml run api mix test $(only)
@bash docker/message.sh "Done running tests"
format:
docker compose run --rm api bash -c "mix format && mix credo --strict"

View file

@ -9,7 +9,7 @@
Mobilizon is your federated organization and mobilization platform. Gather people with a convivial, ethical, and emancipating tool.
<p align="center">
<strong>Developed with ♥ by <a href="https://framasoft.org">Framasoft</a></strong>
<strong>2017 - 2024 Developed with ♥ by <a href="https://framasoft.org">Framasoft</a></strong>
</p>
<p align="center">
@ -20,7 +20,7 @@ Mobilizon is your federated organization and mobilization platform. Gather peopl
## Notes about this fork
The currently deployed `main` branch can be tested at [https://rotes.potsda.mn/](https://rotes.potsda.mn/).
The currently deployed `v4.x` branch can be tested at [https://rotes.potsda.mn/](https://rotes.potsda.mn/).
### Building with Nix

View file

@ -1,7 +1,7 @@
[Mobilizon](https://joinmobilizon.org) takes security, privacy and user control seriously, and we want to put them front and centre of our project.
This document outlines security procedures and general policies for the Mobilizon project.
Framasoft, the Mobilizon maintainer team and community take all security bugs in Mobilizon seriously. Thank you for improving the security of Mobilizon. We appreciate your efforts and responsible disclosure and will make every effort to acknowledge your contributions.
The Mobilizon maintainer team and community take all security bugs in Mobilizon seriously. Thank you for improving the security of Mobilizon. We appreciate your efforts and responsible disclosure and will make every effort to acknowledge your contributions.
### Goals
@ -15,8 +15,6 @@ Framasoft, the Mobilizon maintainer team and community take all security bugs in
* GDPR compliance.
Framasoft is both a developer of open-source/free/libre self-hosted software, and a service provider with users in the European Union. As a result, we are putting user privacy, data sovereignty, and GDPR compliance into our security plans, including asking both the Framasoft community and outside hackers to review our approaches and implementations.
### Challenges
[Mobilizon](https://joinmobilizon.org) will be challenging to keep secure, as it is:
@ -33,14 +31,14 @@ This means there are more attack surfaces compared to typical proprietary, centr
We are committed to working with security researchers to verify, reproduce, and respond to legitimate reported vulnerabilities. You can help us by following these simple guidelines:
* Alert us about the vulnerability as soon as you become aware of it by emailing the lead maintainer at tcit+mobilizon@framasoft.org.
* Alert us about the vulnerability as soon as you become aware of it by emailing the lead maintainer.
* Provide details needed to reproduce and validate the vulnerability and a Proof of Concept (PoC) as soon as possible
* Act in good faith to avoid privacy violations, destruction of data, and interruption or degradation of services
* Do not access or modify users private data, without explicit permission of the owner. Only interact with your own accounts or test accounts for security research purposes;
* Contact Framasoft or a maintainer of the Mobilizon project (or the instance admin) immediately if you do inadvertently encounter user data. Do not view, alter, save, store, transfer, or otherwise access the data, and immediately purge any local information upon reporting the vulnerability;
* Contact a maintainer of the Mobilizon project (or the instance admin) immediately if you do inadvertently encounter user data. Do not view, alter, save, store, transfer, or otherwise access the data, and immediately purge any local information upon reporting the vulnerability;
* The lead maintainer will acknowledge your email within 48 hours, and will send a more detailed response within 48 hours indicating the next steps in handling your report. After the initial reply to your report, the security team will endeavor to keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance.
* Give us time to confirm, determine the affected versions and prepare fixes to correct the issue before disclosing it to other parties (if after waiting a reasonable amount of time, we are clearly unable or unwilling to do anything about it, please do hold us accountable!)
* Please test against a local instance of the software, and refrain from running any Denial of Service or automated testing tools against Framasoft's (and our partners') infrastructure
* Please test against a local instance of the software, and refrain from running any Denial of Service or automated testing tools against the project managers (and their partners') infrastructure
Note : Please report security bugs in third-party modules to the person or team maintaining the module.

View file

@ -36,7 +36,8 @@ config :mobilizon, :instance,
unconfirmed_user_grace_period_hours: 48,
activity_expire_days: 365,
activity_keep_number: 100,
enable_instance_feeds: false,
duration_of_long_event: 30,
enable_instance_feeds: true,
email_from: "noreply@localhost",
email_reply_to: "noreply@localhost"
@ -51,6 +52,7 @@ config :mobilizon, :restrictions, only_groups_can_create_events: false
# Configures the endpoint
config :mobilizon, Mobilizon.Web.Endpoint,
adapter: Bandit.PhoenixAdapter,
url: [
host: "mobilizon.local",
scheme: "https"
@ -134,7 +136,7 @@ config :vite_phx,
environment: config_env(),
# this manifest is different from the Phoenix "cache_manifest.json"!
# optional
vite_manifest: "priv/static/manifest.json",
vite_manifest: "priv/static/.vite/manifest.json",
# optional
dev_server_address: "http://localhost:5173"
@ -204,6 +206,8 @@ config :codepagex, :encodings, [
:"VENDORS/MICSFT/WINDOWS/CP1252"
]
config :gettext, :default_locale, "en"
config :mobilizon, Mobilizon.Web.Gettext, split_module_by: [:locale, :domain]
config :ex_cldr,

View file

@ -5,9 +5,9 @@ config :mobilizon, Mobilizon.Web.Endpoint,
port: String.to_integer(System.get_env("MOBILIZON_INSTANCE_HOST_PORT", "4000"))
],
url: [
host: System.get_env("MOBILIZON_INSTANCE_HOST", "mobilizon.local"),
port: String.to_integer(System.get_env("MOBILIZON_INSTANCE_HOST_PORT", "80")),
scheme: "http"
host: System.get_env("MOBILIZON_INSTANCE_HOST", "localhost"),
port: String.to_integer(System.get_env("MOBILIZON_INSTANCE_HOST_PORT", "4000")),
scheme: System.get_env("MOBILIZON_INSTANCE_SCHEME", "http")
],
secret_key_base: System.get_env("MOBILIZON_INSTANCE_SECRET_KEY_BASE", "changethis"),
debug_errors: true,

View file

@ -1,6 +1,7 @@
# Mobilizon instance configuration
import Config
import Mobilizon.Service.Config.Helpers
{:ok, _} = Application.ensure_all_started(:tls_certificate_check)
@ -49,9 +50,20 @@ config :mobilizon, :instance,
description: "Change this to a proper description of your instance",
hostname: System.get_env("MOBILIZON_INSTANCE_HOST", "mobilizon.lan"),
registrations_open: System.get_env("MOBILIZON_INSTANCE_REGISTRATIONS_OPEN", "false") == "true",
demo: false,
allow_relay: true,
federating: true,
registration_email_allowlist:
System.get_env("MOBILIZON_INSTANCE_REGISTRATIONS_EMAIL_ALLOWLIST", "")
|> String.split(",", trim: true),
registration_email_denylist:
System.get_env("MOBILIZON_INSTANCE_REGISTRATIONS_EMAIL_DENYLIST", "")
|> String.split(",", trim: true),
disable_database_login:
System.get_env("MOBILIZON_INSTANCE_DISABLE_DATABASE_LOGIN", "false") == "true",
default_language: System.get_env("MOBILIZON_INSTANCE_DEFAULT_LANGUAGE", "en"),
demo: System.get_env("MOBILIZON_INSTANCE_DEMO", "false") == "true",
allow_relay: System.get_env("MOBILIZON_INSTANCE_ALLOW_RELAY", "true") == "true",
federating: System.get_env("MOBILIZON_INSTANCE_FEDERATING", "true") == "true",
enable_instance_feeds:
System.get_env("MOBILIZON_INSTANCE_ENABLE_INSTANCE_FEEDS", "true") == "true",
email_from: System.get_env("MOBILIZON_INSTANCE_EMAIL", "noreply@mobilizon.lan"),
email_reply_to: System.get_env("MOBILIZON_REPLY_EMAIL", "noreply@mobilizon.lan")
@ -79,7 +91,7 @@ config :mobilizon, Mobilizon.Web.Email.Mailer,
ssl: System.get_env("MOBILIZON_SMTP_SSL", "false"),
retries: 1,
no_mx_lookups: false,
auth: :if_available
auth: System.get_env("MOBILIZON_SMTP_AUTH", "if_available")
config :geolix,
databases: [
@ -93,13 +105,30 @@ config :geolix,
config :mobilizon, Mobilizon.Web.Upload.Uploader.Local,
uploads: System.get_env("MOBILIZON_UPLOADS", "/var/lib/mobilizon/uploads")
formats =
if System.get_env("MOBILIZON_EXPORTS_FORMAT_CSV_ENABLED", "true") == "true" do
[Mobilizon.Service.Export.Participants.CSV]
else
[]
end
formats =
if System.get_env("MOBILIZON_EXPORTS_FORMAT_PDF_ENABLED", "true") == "true" do
formats ++ [Mobilizon.Service.Export.Participants.PDF]
else
formats
end
formats =
if System.get_env("MOBILIZON_EXPORTS_FORMAT_ODS_ENABLED", "true") == "true" do
formats ++ [Mobilizon.Service.Export.Participants.ODS]
else
formats
end
config :mobilizon, :exports,
path: System.get_env("MOBILIZON_UPLOADS_EXPORTS", "/var/lib/mobilizon/uploads/exports"),
formats: [
Mobilizon.Service.Export.Participants.CSV,
Mobilizon.Service.Export.Participants.PDF,
Mobilizon.Service.Export.Participants.ODS
]
formats: formats
config :tz_world,
data_dir: System.get_env("MOBILIZON_TIMEZONES_DIR", "/var/lib/mobilizon/timezones")
@ -110,3 +139,118 @@ config :web_push_encryption, :vapid_details,
subject: System.get_env("MOBILIZON_WEB_PUSH_ENCRYPTION_SUBJECT", nil),
public_key: System.get_env("MOBILIZON_WEB_PUSH_ENCRYPTION_PUBLIC_KEY", nil),
private_key: System.get_env("MOBILIZON_WEB_PUSH_ENCRYPTION_PRIVATE_KEY", nil)
geospatial_service =
case System.get_env("MOBILIZON_GEOSPATIAL_SERVICE", "Nominatim") do
"Nominatim" -> Mobilizon.Service.Geospatial.Nominatim
"Addok" -> Mobilizon.Service.Geospatial.Addok
"Photon" -> Mobilizon.Service.Geospatial.Photon
"GoogleMaps" -> Mobilizon.Service.Geospatial.GoogleMaps
"MapQuest" -> Mobilizon.Service.Geospatial.MapQuest
"Mimirsbrunn" -> Mobilizon.Service.Geospatial.Mimirsbrunn
"Pelias" -> Mobilizon.Service.Geospatial.Pelias
"Hat" -> Mobilizon.Service.Geospatial.Hat
end
config :mobilizon, Mobilizon.Service.Geospatial, service: geospatial_service
config :mobilizon, Mobilizon.Service.Geospatial.Nominatim,
endpoint:
System.get_env(
"MOBILIZON_GEOSPATIAL_NOMINATIM_ENDPOINT",
"https://nominatim.openstreetmap.org"
),
api_key: System.get_env("MOBILIZON_GEOSPATIAL_NOMINATIM_API_KEY", nil)
config :mobilizon, Mobilizon.Service.Geospatial.Addok,
endpoint:
System.get_env("MOBILIZON_GEOSPATIAL_ADDOK_ENDPOINT", "https://api-adresse.data.gouv.fr")
config :mobilizon, Mobilizon.Service.Geospatial.Photon,
endpoint: System.get_env("MOBILIZON_GEOSPATIAL_PHOTON_ENDPOINT", "https://photon.komoot.de")
config :mobilizon, Mobilizon.Service.Geospatial.GoogleMaps,
api_key: System.get_env("MOBILIZON_GEOSPATIAL_GOOGLE_MAPS_API_KEY", nil),
fetch_place_details: true
config :mobilizon, Mobilizon.Service.Geospatial.MapQuest,
api_key: System.get_env("MOBILIZON_GEOSPATIAL_MAP_QUEST_API_KEY", nil)
config :mobilizon, Mobilizon.Service.Geospatial.Mimirsbrunn,
endpoint: System.get_env("MOBILIZON_GEOSPATIAL_MIMIRSBRUNN_ENDPOINT", nil)
config :mobilizon, Mobilizon.Service.Geospatial.Pelias,
endpoint: System.get_env("MOBILIZON_GEOSPATIAL_PELIAS_ENDPOINT", nil)
sentry_dsn = System.get_env("MOBILIZON_ERROR_REPORTING_SENTRY_DSN", nil)
included_environments = if sentry_dsn, do: ["prod"], else: []
config :sentry,
dsn: sentry_dsn,
included_environments: included_environments,
release: to_string(Application.spec(:mobilizon, :vsn))
config :logger, Sentry.LoggerBackend,
capture_log_messages: true,
level: :error
if sentry_dsn != nil do
config :mobilizon, Mobilizon.Service.ErrorReporting,
adapter: Mobilizon.Service.ErrorReporting.Sentry
end
matomo_enabled = System.get_env("MOBILIZON_FRONT_END_ANALYTICS_MATOMO_ENABLED", "false") == "true"
matomo_endpoint = System.get_env("MOBILIZON_FRONT_END_ANALYTICS_MATOMO_ENDPOINT", nil)
matomo_site_id = System.get_env("MOBILIZON_FRONT_END_ANALYTICS_MATOMO_SITE_ID", nil)
matomo_tracker_file_name =
System.get_env("MOBILIZON_FRONT_END_ANALYTICS_MATOMO_TRACKER_FILE_NAME", "matomo")
matomo_host = host_from_uri(matomo_endpoint)
analytics_providers =
if matomo_enabled do
[Mobilizon.Service.FrontEndAnalytics.Matomo]
else
[]
end
analytics_providers =
if sentry_dsn != nil do
analytics_providers ++ [Mobilizon.Service.FrontEndAnalytics.Sentry]
else
analytics_providers
end
config :mobilizon, :analytics, providers: analytics_providers
matomo_csp =
if matomo_enabled and matomo_host do
[
connect_src: [matomo_host],
script_src: [matomo_host],
img_src: [matomo_host]
]
else
[]
end
config :mobilizon, Mobilizon.Service.FrontEndAnalytics.Matomo,
enabled: matomo_enabled,
host: matomo_endpoint,
siteId: matomo_site_id,
trackerFileName: matomo_tracker_file_name,
csp: matomo_csp
config :mobilizon, Mobilizon.Service.FrontEndAnalytics.Sentry,
enabled: sentry_dsn != nil,
dsn: sentry_dsn,
tracesSampleRate: 1.0,
organization: System.get_env("MOBILIZON_ERROR_REPORTING_SENTRY_ORGANISATION", nil),
project: System.get_env("MOBILIZON_ERROR_REPORTING_SENTRY_PROJECT", nil),
host: System.get_env("MOBILIZON_ERROR_REPORTING_SENTRY_HOST", nil),
csp: [
connect_src:
System.get_env("MOBILIZON_ERROR_REPORTING_SENTRY_HOST", "") |> String.split(" ", trim: true)
]

View file

@ -25,7 +25,7 @@ config :vite_phx,
release_app: :mobilizon,
# Hard code :prod as an environment as :e2e will not be recongnized
environment: :prod,
vite_manifest: "priv/static/manifest.json",
vite_manifest: "priv/static/.vite/manifest.json",
phx_manifest: "priv/static/cache_manifest.json",
dev_server_address: "http://localhost:5173"

View file

@ -2,7 +2,8 @@ import Config
config :mobilizon, :instance,
name: "Test instance",
registrations_open: true
registrations_open: true,
duration_of_long_event: 0
# We don't run a server during test. If one is required,
# you can enable the server option below.

View file

@ -1,40 +1,35 @@
{ lib
, beamPackages
, fetchFromGitHub
, git
, cmake
, nixosTests
, src
, src-config
, mobilizon-js
{
lib,
beam_nox,
fetchFromGitHub,
cmake,
nixosTests,
src,
src-config,
mobilizon-js,
}:
let
inherit (beamPackages) mixRelease buildMix;
inherit (beam_nox.packages.erlang) mixRelease buildMix elixir;
in
mixRelease rec {
pname = "mobilizon";
version = "4.0.2";
# This has to be kept in sync with the version in mix.exs and package.json!
# Otherwise the nginx routing isn't going to work properly.
version = "5.0.0-beta.1";
inherit src;
# See https://github.com/whitfin/cachex/issues/205
# This circumvents a startup error for now
stripDebug = false;
nativeBuildInputs = [ git cmake ];
mixNixDeps = import ./mix.nix {
inherit beamPackages lib;
overrides = (final: prev:
(lib.mapAttrs
(_: value: value.override {
appConfigPath = src-config;
})
prev) // {
fast_html = prev.fast_html.override {
nativeBuildInputs = [ cmake ];
};
# Update deps.nix by running `mix deps.nix`
mixNixDeps = import ./deps.nix {
inherit lib;
beamPackages = beam_nox.packages.erlang;
overrides = (
final: prev:
(lib.mapAttrs (_: value: value.override { appConfigPath = src-config; }) prev)
// {
fast_html = prev.fast_html.override { nativeBuildInputs = [ cmake ]; };
ex_cldr = prev.ex_cldr.overrideAttrs (old: {
# We have to use the GitHub sources, as it otherwise tries to download
# the locales at build time.
@ -42,77 +37,27 @@ mixRelease rec {
owner = "elixir-cldr";
repo = "cldr";
rev = "v${old.version}";
sha256 = assert old.version == "2.37.5";
sha256 =
assert old.version == "2.37.5";
"sha256-T5Qvuo+xPwpgBsqHNZYnTCA4loToeBn1LKTMsDcCdYs=";
};
postInstall = ''
cp $src/priv/cldr/locales/* $out/lib/erlang/lib/ex_cldr-${old.version}/priv/cldr/locales/
'';
});
# Upstream issue: https://github.com/bryanjos/geo_postgis/pull/87
geo_postgis = prev.geo_postgis.overrideAttrs (old: {
propagatedBuildInputs = old.propagatedBuildInputs ++ [ final.ecto ];
});
# The remainder are Git dependencies (and their deps) that are not supported by mix2nix currently.
web_push_encryption = buildMix rec {
name = "web_push_encryption";
version = "0.3.1";
src = fetchFromGitHub {
owner = "danhper";
repo = "elixir-web-push-encryption";
rev = "70f00d06cbd88c9ac382e0ad2539e54448e9d8da";
sha256 = "sha256-b4ZMrt/8n2sPUFtCDRTwXS1qWm5VlYdbx8qC0R0boOA=";
};
beamDeps = with final; [ httpoison jose ];
};
icalendar = buildMix rec {
name = "icalendar";
version = "unstable-2022-04-10";
src = fetchFromGitHub {
owner = "tcitworld";
repo = name;
rev = "1033d922c82a7223db0ec138e2316557b70ff49f";
sha256 = "sha256-N3bJZznNazLewHS4c2B7LP1lgxd1wev+EWVlQ7rOwfU=";
};
beamDeps = with final; [ mix_test_watch ex_doc timex ];
};
rajska = buildMix rec {
name = "rajska";
version = "1.3.3";
src = fetchFromGitHub {
owner = "tcitworld";
repo = name;
rev = "0c036448e261e8be6a512581c592fadf48982d84";
sha256 = "sha256-4pfply1vTAIT2Xvm3kONmrCK05xKfXFvcb8EKoSCXBE=";
};
beamDeps = with final; [ ex_doc credo absinthe excoveralls hammer mock ];
};
exkismet = buildMix rec {
name = "exkismet";
version = "0.0.3";
src = fetchFromGitHub {
owner = "tcitworld";
repo = name;
rev = "8b5485fde00fafbde20f315bec387a77f7358334";
sha256 = "sha256-ttgCWoBKU7VTjZJBhZNtqVF4kN7psBr/qOeR65MbTqw=";
};
beamDeps = with final; [ httpoison ex_doc credo doctor dialyxir ];
};
});
}
);
};
preConfigure = ''
export LANG=C.UTF-8 # fix elixir locale warning
'';
# fix elixir locale warning
env.LANG = "C.UTF-8";
# Install the compiled js part
preBuild =
''
cp -a "${mobilizon-js}/_napalm-install/priv/static" ./priv
chmod 770 -R ./priv
'';
preBuild = ''
cp -a "${mobilizon-js}/_napalm-install/priv/static" ./priv
chmod 770 -R ./priv
'';
postBuild = ''
mix phx.digest --no-deps-check
@ -128,12 +73,15 @@ mixRelease rec {
ln -s ${ex_cldr.src}/priv/cldr/locales $out/lib/ex_cldr-${ex_cldr.version}/priv/cldr/locales
'';
passthru.elixirPackage = beamPackages.elixir;
passthru.elixirPackage = elixir;
meta = with lib; {
description = "Mobilizon is an online tool to help manage your events, your profiles and your groups";
homepage = "https://joinmobilizon.org/";
license = licenses.agpl3Plus;
maintainers = with maintainers; [ minijackson erictapen ];
maintainers = with maintainers; [
minijackson
erictapen
];
};
}

2226
deps.nix Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
ARG IMAGE="elixir:1.15"
ARG IMAGE="elixir:1.16"
FROM ${IMAGE} as build
SHELL ["/bin/bash", "-c"]

View file

@ -9,7 +9,7 @@ COPY . .
RUN npm install && npm run build
# Then, build the application binary
FROM elixir:1.15-alpine AS builder
FROM elixir:1.16-alpine AS builder
# Fix qemu segfault on arm64
# See https://github.com/plausible/analytics/pull/2879 and https://github.com/erlang/otp/pull/6340

View file

@ -1,11 +1,10 @@
FROM elixir:latest
LABEL maintainer="Thomas Citharel <thomas.citharel@framasoft.org>"
ENV REFRESHED_AT=2023-11-20
ENV REFRESHED_AT=2024-02-29
RUN apt-get update -yq && apt-get install -yq ca-certificates build-essential inotify-tools postgresql-client git curl gnupg xvfb libgtk-3-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 cmake exiftool python3-pip python3-setuptools
RUN mkdir -p /etc/apt/keyrings && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && apt-get update && apt-get install nodejs -yq
RUN npm install -g wait-on
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN mix local.hex --force && mix local.rebar --force
RUN pip3 --no-cache-dir install -Iv weasyprint pyexcel_ods3
RUN pip --no-cache-dir install --break-system-packages weasyprint pyexcel-ods3
RUN curl https://dbip.mirror.framasoft.org/files/dbip-city-lite-latest.mmdb --output GeoLite2-City.mmdb -s && mkdir -p /usr/share/GeoIP && mv GeoLite2-City.mmdb /usr/share/GeoIP/

View file

@ -26,11 +26,11 @@
]
},
"locked": {
"lastModified": 1703102458,
"narHash": "sha256-3pOV731qi34Q2G8e2SqjUXqnftuFrbcq+NdagEZXISo=",
"lastModified": 1717929455,
"narHash": "sha256-BiI5xWygriOJuNISnGAeL0KYxrEMnjgpg+7wDskVBhI=",
"owner": "nix-community",
"repo": "napalm",
"rev": "edcb26c266ca37c9521f6a97f33234633cbec186",
"rev": "e1babff744cd278b56abe8478008b4a9e23036cf",
"type": "github"
},
"original": {
@ -41,11 +41,11 @@
},
"nix-filter": {
"locked": {
"lastModified": 1705332318,
"narHash": "sha256-kcw1yFeJe9N4PjQji9ZeX47jg0p9A0DuU4djKvg1a7I=",
"lastModified": 1710156097,
"narHash": "sha256-1Wvk8UP7PXdf8bCCaEoMnOT1qe5/Duqgj+rL8sRQsSM=",
"owner": "numtide",
"repo": "nix-filter",
"rev": "3449dc925982ad46246cfc36469baf66e1b64f17",
"rev": "3342559a24e85fc164b295c3444e8a139924675b",
"type": "github"
},
"original": {
@ -56,11 +56,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1706550542,
"narHash": "sha256-UcsnCG6wx++23yeER4Hg18CXWbgNpqNXcHIo5/1Y+hc=",
"lastModified": 1726463316,
"narHash": "sha256-gI9kkaH0ZjakJOKrdjaI/VbaMEo9qBbSUl93DnU7f4c=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "97b17f32362e475016f942bbdfda4a4a72a8a652",
"rev": "99dc8785f6a0adac95f5e2ab05cc2e1bf666d172",
"type": "github"
},
"original": {

507
flake.nix
View file

@ -8,20 +8,27 @@
napalm.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = { self, nixpkgs, nix-filter, napalm }:
outputs =
{
self,
nixpkgs,
nix-filter,
napalm,
}:
let
forAllSystems = f: nixpkgs.lib.genAttrs
[ "x86_64-linux" "aarch64-linux" ]
(system: f system);
nixpkgsFor = forAllSystems (
system:
import nixpkgs { inherit system; }
);
forAllSystems =
f:
nixpkgs.lib.genAttrs [
"x86_64-linux"
"aarch64-linux"
] (system: f system);
nixpkgsFor = forAllSystems (system: import nixpkgs { inherit system; });
filter = nix-filter.lib;
in
{
packages = forAllSystems (system:
packages = forAllSystems (
system:
let
pkgs = nixpkgsFor.${system};
# Directories that are neither needed for building the frontend nor the backend.
@ -55,9 +62,6 @@
};
mobilizon-frontend =
let
nodejs = pkgs.nodejs-18_x;
in
napalm.legacyPackages."${system}".buildPackage
(filter {
root = ./.;
@ -70,43 +74,183 @@
] ++ unrelatedDirs;
})
{
inherit nodejs;
inherit (pkgs) nodejs;
nativeBuildInputs = [ pkgs.imagemagick ];
npmCommands = [ "npm install" "npm run build" ];
npmCommands = [
"npm install"
"npm run build"
];
# Keep this in sync with the content of ./patches/
customPatchPackages = {
vue-i18n-extract."2.0.7" = pkgs: prev: {
preConfigure = ''
${pkgs.git}/bin/git apply -p3 ${./patches/vue-i18n-extract+2.0.7.patch}
'';
};
};
};
default = self.packages."${system}".mobilizon;
}
);
# Update local Mobilizon definition
update =
pkgs.writeShellScriptBin "update" ''
set -eou pipefail
${pkgs.mix2nix}/bin/mix2nix ./mix.lock > mix.nix
'';
});
devShells = forAllSystems (system:
let pkgs = nixpkgsFor.${system};
in {
default =
pkgs.mkShell {
buildInputs = with pkgs; [
elixir
mix2nix
cmake
imagemagick
nodejs-18_x
];
devShells = forAllSystems (
system:
let
pkgs = nixpkgsFor.${system};
settingsFormat = pkgs.formats.elixirConf { };
mobilizonConfig = settingsFormat.generate "runtime.exs" {
":mobilizon" = {
"Mobilizon.Web.Endpoint" = {
server = true;
url.host = "mobilizon.dev";
http = {
ip = settingsFormat.lib.mkTuple [
0
0
0
0
0
0
0
1
];
port = 4000;
};
secret_key_base = "2q/l1WDx3RQQy7gZ1k001//6nc66moWUEJQyGuMK/z3zPLYW6FYtIgCkUzGP0+X/";
};
"Mobilizon.Web.Auth.Guardian" = {
secret_key = "N8x7/tf0kInLFS2poO22g6OGPiMjSrDEhmk29nFqV35q7hQ0DtBt/cRYCsqBNp2L";
};
":instance" = {
name = "Mobilizon";
description = "Change this to a proper description of your instance";
hostname = "mobilizon.dev";
registrations_open = true;
email_from = "noreply@mobilizon.dev";
email_reply_to = "noreply@mobilizon.dev";
};
"Mobilizon.Storage.Repo" = {
adapter = settingsFormat.lib.mkAtom "Ecto.Adapters.Postgres";
pool_size = 10;
username = "mobilizon";
database = "mobilizon";
socket_dir = "/var/run/postgresql";
};
};
});
};
in
{
default = pkgs.mkShell {
MIX_ENV = "dev";
PGUSER = "mobilizon";
PGDATABASE = "mobilizon";
buildInputs = with pkgs; [
elixir
cmake
imagemagick
nodejs
inotify-tools
(pkgs.writeShellApplication {
name = "build";
runtimeInputs = [
elixir
nodejs
];
text = ''
mix deps.get
mix deps.nix
mix deps.compile
mix phx.digest
npm install
npm run build
'';
})
(pkgs.writeShellApplication {
name = "setup";
runtimeInputs = [
elixir
postgresql
];
text = ''
cat ${mobilizonConfig} > config/runtime.exs
# We assume the database already exists
sudo -u postgres psql -d mobilizon << SQL
create extension if not exists postgis;
create extension if not exists unaccent;
create extension if not exists pg_trgm;
SQL
mix ecto.migrate
'';
})
(pkgs.writeShellApplication {
name = "start";
runtimeInputs = [ elixir ];
text = ''
mix phx.server
'';
})
(pkgs.writeShellApplication {
name = "clean";
runtimeInputs = [ postgresql ];
text = ''
rm -rf deps/ _build/ node_modules/
sudo -u postgres psql -c "DROP DATABASE mobilizon;"
sudo systemctl restart postgresql.service
'';
})
];
};
}
);
overlays.default = final: prev: {
inherit (self.packages."${prev.system}") mobilizon;
};
nixosModules.devSetup =
{
config,
lib,
pkgs,
...
}:
let
cfg = config.mobilizonDevEnvironment;
in
{
options.mobilizonDevEnvironment = {
enable = lib.mkEnableOption (lib.mdDoc "development environment for Mobilizon");
user = lib.mkOption {
type = lib.types.str;
description = "Unix user that runs the backend application to connect to the database";
};
};
config = lib.mkIf cfg.enable {
services.postgresql = {
enable = true;
ensureDatabases = [ "mobilizon" ];
ensureUsers = [
{
name = "mobilizon";
ensureDBOwnership = true;
}
];
extraPlugins = with config.services.postgresql.package.pkgs; [ postgis ];
identMap = ''
map-mobilizon ${cfg.user} mobilizon
'';
authentication = ''
local all mobilizon ident map=map-mobilizon
'';
};
};
};
overlays.default = final: prev: { inherit (self.packages."${prev.system}") mobilizon; };
checks = forAllSystems (system: {
inherit (self.packages.${system}) mobilizon update;
inherit (self.packages.${system}) mobilizon;
nixosTest =
let
pkgsMobilizon = import nixpkgs {
@ -114,7 +258,7 @@
overlays = [ self.overlays.default ];
};
certs = import "${nixpkgs}/nixos/tests/common/acme/server/snakeoil-certs.nix";
test = import ./nixos-test.nix { inherit certs; };
test = import ./integration-test.nix { inherit certs; };
in
pkgsMobilizon.nixosTest test;
});
@ -122,120 +266,197 @@
lib = {
# Patch the logos in the source tree of a mobilizon-frontend package before building.
# Can be used to construct the argument for .overrideAttrs on mobilizon-frontend.
mobilizonLogosOverride = icons:
mobilizonLogosOverride =
icons:
let
inherit (icons) logo favicon;
in
old: {
postPatch = ''
cp '${logo}' src/assets/logo.svg
postPatch =
''
cp '${logo}' src/assets/logo.svg
magick convert \
-resize x16 \
-gravity center \
-crop 16x16+0+0 \
-flatten \
-colors 256 \
'${favicon}' \
public/img/icons/favicon-16x16.png
magick convert \
-resize x32 \
-gravity center \
-crop 32x32+0+0 \
-flatten \
-colors 256 \
'${favicon}' \
public/img/icons/favicon-32x32.png
magick convert \
-resize x16 \
-gravity center \
-crop 16x16+0+0 \
-flatten \
-colors 256 \
'${favicon}' \
favicon-16x16.ico
magick convert \
-resize x32 \
-gravity center \
-crop 32x32+0+0 \
-flatten \
-colors 256 \
'${favicon}' \
favicon-32x32.ico
magick convert \
-resize x48 \
-gravity center \
-crop 48x48+0+0 \
-flatten \
-colors 256 \
'${favicon}' \
favicon-48x48.ico
magick convert \
favicon-16x16.ico \
favicon-32x32.ico \
favicon-48x48.ico \
public/favicon.ico
rm favicon-16x16.ico favicon-32x32.ico favicon-48x48.ico
cp '${favicon}' public/img/icons/favicon.svg
cp '${favicon}' public/img/icons/safari-pinned-tab.svg
magick convert \
'${favicon}' \
-gravity center \
-extent 630x350 \
public/img/mobilizon_default_card.png
magick convert \
-background '#e08c96' \
'${logo}' \
-resize 366x108 \
public/img/mobilizon_logo.png
'' + nixpkgs.lib.concatMapStrings
({ resize, filename }: ''
magick convert \
-resize x${resize} \
-resize x16 \
-gravity center \
-crop 16x16+0+0 \
-flatten \
-colors 256 \
'${favicon}' \
public/img/icons/${filename}
public/img/icons/favicon-16x16.png
'')
[
{ resize = "180"; filename = "apple-touch-icon.png"; }
{ resize = "180"; filename = "apple-touch-icon-180x180.png"; }
{ resize = "152"; filename = "apple-touch-icon-152x152.png"; }
{ resize = "120"; filename = "apple-touch-icon-120x120.png"; }
{ resize = "76"; filename = "apple-touch-icon-76x76.png"; }
{ resize = "60"; filename = "apple-touch-icon-60x60.png"; }
{ resize = "192"; filename = "android-chrome-192x192.png"; }
{ resize = "512"; filename = "android-chrome-512x512.png"; }
{ resize = "192"; filename = "android-chrome-maskable-192x192.png"; }
{ resize = "512"; filename = "android-chrome-maskable-512x512.png"; }
{ resize = "128"; filename = "badge-128x128.png"; }
{ resize = "144"; filename = "icon-144x144.png"; }
{ resize = "168"; filename = "icon-168x168.png"; }
{ resize = "256"; filename = "icon-256x256.png"; }
{ resize = "48"; filename = "icon-48x48.png"; }
{ resize = "72"; filename = "icon-72x72.png"; }
{ resize = "96"; filename = "icon-96x96.png"; }
{ resize = "144"; filename = "msapplication-icon-144x144.png"; }
{ resize = "150"; filename = "mstile-150x150.png"; }
{ resize = "192"; filename = "android-chrome-192x192.png"; }
{ resize = "512"; filename = "android-chrome-512x512.png"; }
{ resize = "192"; filename = "android-chrome-maskable-192x192.png"; }
{ resize = "512"; filename = "android-chrome-maskable-512x512.png"; }
];
magick convert \
-resize x32 \
-gravity center \
-crop 32x32+0+0 \
-flatten \
-colors 256 \
'${favicon}' \
public/img/icons/favicon-32x32.png
magick convert \
-resize x16 \
-gravity center \
-crop 16x16+0+0 \
-flatten \
-colors 256 \
'${favicon}' \
favicon-16x16.ico
magick convert \
-resize x32 \
-gravity center \
-crop 32x32+0+0 \
-flatten \
-colors 256 \
'${favicon}' \
favicon-32x32.ico
magick convert \
-resize x48 \
-gravity center \
-crop 48x48+0+0 \
-flatten \
-colors 256 \
'${favicon}' \
favicon-48x48.ico
magick convert \
favicon-16x16.ico \
favicon-32x32.ico \
favicon-48x48.ico \
public/favicon.ico
rm favicon-16x16.ico favicon-32x32.ico favicon-48x48.ico
cp '${favicon}' public/img/icons/favicon.svg
cp '${favicon}' public/img/icons/safari-pinned-tab.svg
magick convert \
'${favicon}' \
-gravity center \
-extent 630x350 \
public/img/mobilizon_default_card.png
magick convert \
-background '#e08c96' \
'${logo}' \
-resize 366x108 \
public/img/mobilizon_logo.png
''
+
nixpkgs.lib.concatMapStrings
(
{ resize, filename }:
''
magick convert \
-resize x${resize} \
'${favicon}' \
public/img/icons/${filename}
''
)
[
{
resize = "180";
filename = "apple-touch-icon.png";
}
{
resize = "180";
filename = "apple-touch-icon-180x180.png";
}
{
resize = "152";
filename = "apple-touch-icon-152x152.png";
}
{
resize = "120";
filename = "apple-touch-icon-120x120.png";
}
{
resize = "76";
filename = "apple-touch-icon-76x76.png";
}
{
resize = "60";
filename = "apple-touch-icon-60x60.png";
}
{
resize = "192";
filename = "android-chrome-192x192.png";
}
{
resize = "512";
filename = "android-chrome-512x512.png";
}
{
resize = "192";
filename = "android-chrome-maskable-192x192.png";
}
{
resize = "512";
filename = "android-chrome-maskable-512x512.png";
}
{
resize = "128";
filename = "badge-128x128.png";
}
{
resize = "144";
filename = "icon-144x144.png";
}
{
resize = "168";
filename = "icon-168x168.png";
}
{
resize = "256";
filename = "icon-256x256.png";
}
{
resize = "48";
filename = "icon-48x48.png";
}
{
resize = "72";
filename = "icon-72x72.png";
}
{
resize = "96";
filename = "icon-96x96.png";
}
{
resize = "144";
filename = "msapplication-icon-144x144.png";
}
{
resize = "150";
filename = "mstile-150x150.png";
}
{
resize = "192";
filename = "android-chrome-192x192.png";
}
{
resize = "512";
filename = "android-chrome-512x512.png";
}
{
resize = "192";
filename = "android-chrome-maskable-192x192.png";
}
{
resize = "512";
filename = "android-chrome-maskable-512x512.png";
}
];
};
};
formatter = forAllSystems (system: nixpkgsFor.${system}.nixfmt-rfc-style);
};
}

View file

@ -7,7 +7,10 @@ in
{
name = "mobilizon";
meta.maintainers = with lib.maintainers; [ minijackson erictapen ];
meta.maintainers = with lib.maintainers; [
minijackson
erictapen
];
nodes.server =
{ pkgs, ... }:

View file

@ -105,6 +105,9 @@ defmodule Mobilizon.Federation.ActivityPub.Fetcher do
{:error, %Ecto.Changeset{} = err} ->
{:error, err}
{:error, {:error, %Ecto.Changeset{} = err}} ->
{:error, err}
:error ->
{:error, :transmogrifier_error}
end

View file

@ -7,6 +7,7 @@ defmodule Mobilizon.Federation.ActivityPub.Publisher do
alias Mobilizon.Config
alias Mobilizon.Federation.ActivityPub.{Activity, Federator, Relay, Transmogrifier, Visibility}
alias Mobilizon.Federation.HTTPSignatures.Signature
alias Mobilizon.Service.HTTP.ActivityPub, as: ActivityPubClient
require Logger
import Mobilizon.Federation.ActivityPub.Utils,
@ -95,16 +96,16 @@ defmodule Mobilizon.Federation.ActivityPub.Publisher do
date: date
})
Tesla.post(
inbox,
json,
headers: [
{"Content-Type", "application/activity+json"},
{"signature", signature},
{"digest", digest},
{"date", date}
]
)
headers = [
{"Content-Type", "application/activity+json"},
{"signature", signature},
{"digest", digest},
{"date", date}
]
client = ActivityPubClient.client(headers: headers)
ActivityPubClient.post(client, inbox, json)
end
@spec convert_followers_in_recipients(list(String.t())) :: {list(String.t()), list(String.t())}

View file

@ -71,8 +71,10 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
case Discussions.get_comment_from_url_with_preload(object["id"]) do
{:error, :comment_not_found} ->
case Converter.Comment.as_to_model_data(object) do
%{visibility: visibility, attributed_to_id: attributed_to_id} = object_data
when visibility === :private and is_nil(attributed_to_id) ->
%{visibility: visibility, attributed_to_id: attributed_to_id, actor_id: actor_id} =
object_data
when visibility === :private and
(is_nil(attributed_to_id) or actor_id == attributed_to_id) ->
Actions.Create.create(:conversation, object_data, false)
object_data when is_map(object_data) ->

View file

@ -6,10 +6,13 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
internal one, and back.
"""
alias Cldr.DateTime.Formatter
alias Mobilizon.Actors.Actor
alias Mobilizon.Addresses.Address
alias Mobilizon.Events.Categories
alias Mobilizon.Events.Event, as: EventModel
alias Mobilizon.Events.EventOptions
alias Mobilizon.Medias.Media
alias Mobilizon.Federation.ActivityStream.{Converter, Convertible}
@ -29,7 +32,14 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
maybe_fetch_actor_and_attributed_to_id: 1,
process_pictures: 2,
get_address: 1,
fetch_actor: 1
fetch_actor: 1,
visibility_public?: 1
]
import Mobilizon.Service.Metadata.Utils,
only: [
datetime_to_string: 3,
render_address!: 1
]
require Logger
@ -146,7 +156,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
"anonymousParticipationEnabled" => event.options.anonymous_participation,
"attachment" => Enum.map(event.metadata, &EventMetadataConverter.metadata_to_as/1),
"draft" => event.draft,
# Remove me in MBZ 5.x
# TODO: Remove me in MBZ 5.x
"ical:status" => event.status |> to_string |> String.upcase(),
"status" => event.status |> to_string |> String.upcase(),
"id" => event.url,
@ -154,7 +164,8 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
"inLanguage" => event.language,
"timezone" => event.options.timezone,
"contacts" => Enum.map(event.contacts, & &1.url),
"isOnline" => event.options.is_online
"isOnline" => event.options.is_online,
"summary" => event_summary(event)
}
|> maybe_add_physical_address(event)
|> maybe_add_event_picture(event)
@ -216,7 +227,8 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
defp get_metdata(_), do: []
defp get_visibility(object), do: if(@ap_public in object["to"], do: :public, else: :unlisted)
defp get_visibility(object),
do: if(visibility_public?(object["to"]), do: :public, else: :unlisted)
@spec date_to_string(DateTime.t() | nil) :: String.t()
defp date_to_string(nil), do: nil
@ -341,4 +353,47 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
_participant_count
),
do: nil
def event_summary(%EventModel{
begins_on: begins_on,
physical_address: address,
options: %EventOptions{timezone: timezone},
language: language
}) do
begins_on = build_begins_on(begins_on, timezone)
begins_on
|> datetime_to_string(language || "en", :long)
|> (&[&1]).()
|> add_timezone(begins_on)
|> maybe_build_address(address)
|> Enum.join(" - ")
end
@spec build_begins_on(DateTime.t(), String.t() | nil) :: DateTime.t()
defp build_begins_on(begins_on, nil), do: begins_on
defp build_begins_on(begins_on, timezone) do
case DateTime.shift_zone(begins_on, timezone) do
{:ok, begins_on} -> begins_on
{:error, _err} -> begins_on
end
end
defp add_timezone(elements, %DateTime{} = begins_on) do
elements ++ [Formatter.zone_gmt(begins_on)]
end
@spec maybe_build_address(list(String.t()), Address.t() | nil) :: list(String.t())
defp maybe_build_address(elements, %Address{} = address) do
elements ++ [render_address!(address)]
rescue
# If the address is not renderable
e in ArgumentError ->
require Logger
Logger.error(Exception.format(:error, e, __STACKTRACE__))
elements
end
defp maybe_build_address(elements, _address), do: elements
end

View file

@ -9,13 +9,9 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Media do
alias Mobilizon.Federation.ActivityStream
alias Mobilizon.Medias
alias Mobilizon.Medias.Media, as: MediaModel
alias Mobilizon.Service.HTTP.RemoteMediaDownloaderClient
alias Mobilizon.Web.Upload
@http_options [
ssl: [{:versions, [:"tlsv1.2"]}]
]
@doc """
Convert a media struct to an ActivityStream representation.
"""
@ -65,7 +61,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Media do
defp upload_media(media_url, ""), do: upload_media(media_url, "unknown")
defp upload_media(media_url, name) do
case Tesla.get(media_url, opts: @http_options) do
case RemoteMediaDownloaderClient.get(media_url) do
{:ok, %{body: body}} ->
case Upload.store(%{body: body, name: name}) do
{:ok, %{url: _url} = uploaded} ->

View file

@ -15,7 +15,8 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Post do
import Mobilizon.Federation.ActivityStream.Converter.Utils,
only: [
process_pictures: 2
process_pictures: 2,
visibility_public?: 1
]
import Mobilizon.Service.Guards, only: [is_valid_string: 1]
@ -134,14 +135,12 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Post do
)
end
@ap_public "https://www.w3.org/ns/activitystreams#Public"
defp get_visibility(%{"to" => to}, %Actor{
followers_url: followers_url,
members_url: members_url
}) do
cond do
@ap_public in to -> :public
visibility_public?(to) -> :public
followers_url in to -> :unlisted
members_url in to -> :private
end

View file

@ -205,9 +205,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Utils do
@spec process_pictures(map(), integer()) :: Keyword.t()
def process_pictures(object, actor_id) do
attachements = Map.get(object, "attachment", [])
{banner, media_attachements} = get_medias(attachements)
{banner, media_attachements} = get_medias(object)
media_attachements_map =
media_attachements
@ -259,24 +257,46 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Utils do
do: String.replace(body, old_url, new_url)
@spec get_medias(list(map())) :: {map(), list(map())}
defp get_medias(attachments) do
banner = get_banner_picture(attachments)
{banner, Enum.filter(attachments, &(&1["type"] == "Document" && &1["url"] != banner["url"]))}
def get_medias(object) do
banner = get_banner_picture(object)
attachments = Map.get(object, "attachment", [])
{banner, Enum.filter(attachments, &(valid_banner_media?(&1) && &1["url"] != banner["url"]))}
end
@spec get_banner_picture(list(map())) :: map()
defp get_banner_picture(attachments) do
# Prefer media with
media_with_picture_name =
Enum.find(attachments, &(&1["type"] == "Document" && &1["name"] == @banner_picture_name))
@spec get_banner_picture(map()) :: map()
defp get_banner_picture(object) do
attachments = Map.get(object, "attachment", [])
image = Map.get(object, "image", %{})
case media_with_picture_name do
# If no banner found, use the first media
nil -> Enum.find(attachments, &(&1["type"] == "Document"))
media_with_picture_name -> media_with_picture_name
media_with_picture_name =
Enum.find(attachments, &(valid_banner_media?(&1) && &1["name"] == @banner_picture_name))
cond do
# Check if the "image" key is set and of type "Document" or "Image"
is_nil(media_with_picture_name) and valid_banner_media?(image) ->
image
is_nil(media_with_picture_name) and Enum.find(attachments, &valid_banner_media?/1) ->
Enum.find(attachments, &valid_banner_media?/1)
!is_nil(media_with_picture_name) ->
media_with_picture_name
true ->
nil
end
end
@spec valid_banner_media?(map()) :: boolean()
defp valid_banner_media?(media) do
media |> Map.get("type") |> valid_attachment_type?()
end
@spec valid_attachment_type?(any()) :: boolean()
defp valid_attachment_type?(type) do
type in ["Document", "Image"]
end
@spec get_address(map | binary | nil) :: Address.t() | nil
def get_address(text_address) when is_binary(text_address) do
get_address(%{"type" => "Place", "name" => text_address})
@ -315,4 +335,13 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Utils do
nil
end
end
@ap_public "https://www.w3.org/ns/activitystreams#Public"
@spec visibility_public?(String.t() | list(String.t())) :: boolean()
def visibility_public?(to) when is_binary(to), do: visibility_public?([to])
def visibility_public?(to) when is_list(to) do
!MapSet.disjoint?(MapSet.new(to), MapSet.new([@ap_public, "as:Public", "Public"]))
end
end

View file

@ -57,15 +57,25 @@ defmodule Mobilizon.GraphQL.API.Events do
defp process_picture(%{media_id: _picture_id} = args, _), do: args
defp process_picture(%{media: media}, %Actor{id: actor_id}) do
with uploaded when is_map(uploaded) <-
media
|> Map.get(:file)
|> Utils.make_media_data(description: Map.get(media, :name)) do
# case url
if Map.has_key?(media, :url) do
%{
file: Map.take(uploaded, [:url, :name, :content_type, :size]),
metadata: Map.take(uploaded, [:width, :height, :blurhash]),
file: %{"url" => media.url, "name" => media.name},
actor_id: actor_id
}
# case upload
else
with uploaded when is_map(uploaded) <-
media
|> Map.get(:file)
|> Utils.make_media_data(description: Map.get(media, :name)) do
%{
file: Map.take(uploaded, [:url, :name, :content_type, :size]),
metadata: Map.take(uploaded, [:width, :height, :blurhash]),
actor_id: actor_id
}
end
end
end

View file

@ -56,7 +56,8 @@ defmodule Mobilizon.GraphQL.API.Search do
minimum_visibility: Map.get(args, :minimum_visibility, :public),
current_actor_id: Map.get(args, :current_actor_id),
exclude_my_groups: Map.get(args, :exclude_my_groups, false),
exclude_stale_actors: true
exclude_stale_actors: true,
local_only: Map.get(args, :search_target, :internal) == :self
],
page,
limit
@ -94,7 +95,13 @@ defmodule Mobilizon.GraphQL.API.Search do
{:ok, service.search_events(Keyword.new(args, fn {k, v} -> {k, v} end))}
else
{:ok, Events.build_events_for_search(Map.put(args, :term, term), page, limit)}
results =
args
|> Map.put(:term, term)
|> Map.put(:local_only, Map.get(args, :search_target, :internal) == :self)
|> Events.build_events_for_search(page, limit)
{:ok, results}
end
end
end

View file

@ -5,11 +5,10 @@ defmodule Mobilizon.GraphQL.Resolvers.Admin do
import Mobilizon.Users.Guards
alias Mobilizon.{Actors, Admin, Config, Events, Instances, Users}
alias Mobilizon.{Actors, Admin, Config, Events, Instances, Media, Users}
alias Mobilizon.Actors.{Actor, Follower}
alias Mobilizon.Admin.{ActionLog, Setting}
alias Mobilizon.Admin.{ActionLog, Setting, SettingMedia}
alias Mobilizon.Cldr.Language
alias Mobilizon.Config
alias Mobilizon.Discussions.Comment
alias Mobilizon.Events.Event
alias Mobilizon.Federation.ActivityPub.{Actions, Relay}
@ -20,6 +19,9 @@ defmodule Mobilizon.GraphQL.Resolvers.Admin do
alias Mobilizon.Storage.Page
alias Mobilizon.Users.User
alias Mobilizon.Web.Email
alias Mobilizon.GraphQL.Resolvers.Media, as: MediaResolver
import Mobilizon.Web.Gettext
require Logger
@ -268,8 +270,11 @@ defmodule Mobilizon.GraphQL.Resolvers.Admin do
with {:ok, res} <- Admin.save_settings("instance", args),
res <-
res
|> Enum.map(fn {key, %Setting{value: value}} ->
{key, Admin.get_setting_value(value)}
|> Enum.map(fn {key, val} ->
case val do
%Setting{value: value} -> {key, Admin.get_setting_value(value)}
%SettingMedia{media: media} -> {key, media}
end
end)
|> Enum.into(%{}),
:ok <- eventually_update_instance_actor(res) do
@ -284,6 +289,38 @@ defmodule Mobilizon.GraphQL.Resolvers.Admin do
dgettext("errors", "You need to be logged-in and an administrator to save admin settings")}
end
@spec get_media_setting(any(), any(), Absinthe.Resolution.t()) ::
{:ok, Media.t()} | {:error, String.t()}
def get_media_setting(_parent, %{group: group, name: name}, %{
context: %{current_user: %User{role: role}}
})
when is_admin(role) do
{:ok, MediaResolver.transform_media(Admin.get_admin_setting_media(group, name, nil))}
end
def get_media_setting(_parent, _args, _resolution) do
{:error,
dgettext("errors", "You need to be logged-in and an administrator to access admin settings")}
end
@spec get_instance_logo(any(), any(), Absinthe.Resolution.t()) ::
{:ok, Media.t() | nil} | {:error, String.t()}
def get_instance_logo(parent, _args, resolution) do
get_media_setting(parent, %{group: "instance", name: "instance_logo"}, resolution)
end
@spec get_instance_favicon(any(), any(), Absinthe.Resolution.t()) ::
{:ok, Media.t() | nil} | {:error, String.t()}
def get_instance_favicon(parent, _args, resolution) do
get_media_setting(parent, %{group: "instance", name: "instance_favicon"}, resolution)
end
@spec get_default_picture(any(), any(), Absinthe.Resolution.t()) ::
{:ok, Media.t() | nil} | {:error, String.t()}
def get_default_picture(parent, _args, resolution) do
get_media_setting(parent, %{group: "instance", name: "default_picture"}, resolution)
end
@spec update_user(any, map(), Absinthe.Resolution.t()) ::
{:error, :invalid_argument | :user_not_found | binary | Ecto.Changeset.t()}
| {:ok, Mobilizon.Users.User.t()}

View file

@ -5,8 +5,11 @@ defmodule Mobilizon.GraphQL.Resolvers.Config do
alias Mobilizon.Config
alias Mobilizon.Events.Categories
alias Mobilizon.Medias.Media
alias Mobilizon.Service.{AntiSpam, FrontEndAnalytics}
alias Mobilizon.GraphQL.Resolvers.Media, as: MediaResolver
@doc """
Gets config.
"""
@ -31,6 +34,16 @@ defmodule Mobilizon.GraphQL.Resolvers.Config do
{:ok, data}
end
@spec instance_logo(any(), map(), Absinthe.Resolution.t()) :: {:ok, Media.t()}
def instance_logo(_parent, _params, _resolution) do
{:ok, MediaResolver.transform_media(Config.instance_logo())}
end
@spec default_picture(any(), map(), Absinthe.Resolution.t()) :: {:ok, Media.t()}
def default_picture(_parent, _params, _resolution) do
{:ok, MediaResolver.transform_media(Config.default_picture())}
end
@spec terms(any(), map(), Absinthe.Resolution.t()) :: {:ok, map()}
def terms(_parent, %{locale: locale}, _resolution) do
type = Config.instance_terms_type()
@ -94,10 +107,15 @@ defmodule Mobilizon.GraphQL.Resolvers.Config do
registrations_allowlist: Config.instance_registrations_allowlist?(),
contact: Config.contact(),
demo_mode: Config.instance_demo_mode?(),
long_events: Config.instance_long_events?(),
description: Config.instance_description(),
long_description: Config.instance_long_description(),
slogan: Config.instance_slogan(),
languages: Config.instance_languages(),
instance_logo: Config.instance_logo(),
primary_color: Config.primary_color(),
secondary_color: Config.secondary_color(),
default_picture: Config.default_picture(),
anonymous: %{
participation: %{
allowed: Config.anonymous_participation?(),

View file

@ -156,6 +156,9 @@ defmodule Mobilizon.GraphQL.Resolvers.Conversation do
{:ok, conversation_to_view(conversation, conversation_participant_actor)}
{:error, %Ecto.Changeset{} = changeset} ->
{:error, changeset}
{:error, :empty_participants} ->
{:error,
dgettext(

View file

@ -69,13 +69,31 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
@spec list_events(any(), map(), Absinthe.Resolution.t()) ::
{:ok, Page.t(Event.t())} | {:error, :events_max_limit_reached}
def list_events(
_parent,
%{
page: page,
limit: limit,
order_by: order_by,
direction: direction,
longevents: longevents,
location: location,
radius: radius
},
_resolution
)
when limit < @event_max_limit do
{:ok,
Events.list_events(page, limit, order_by, direction, true, longevents, location, radius)}
end
def list_events(
_parent,
%{page: page, limit: limit, order_by: order_by, direction: direction},
_resolution
)
when limit < @event_max_limit do
{:ok, Events.list_events(page, limit, order_by, direction)}
{:ok, Events.list_events(page, limit, order_by, direction, true)}
end
def list_events(_parent, %{page: _page, limit: _limit}, _resolution) do

View file

@ -18,6 +18,10 @@ defmodule Mobilizon.GraphQL.Resolvers.Media do
do_fetch_media(media_id)
end
def media(%{media_id: media_id} = _parent, _args, _resolution) do
do_fetch_media(media_id)
end
def media(%{picture: media} = _parent, _args, _resolution), do: {:ok, media}
def media(_parent, %{id: media_id}, _resolution), do: do_fetch_media(media_id)
def media(_parent, _args, _resolution), do: {:ok, nil}
@ -133,8 +137,10 @@ defmodule Mobilizon.GraphQL.Resolvers.Media do
def user_size(_parent, _args, _resolution), do: {:error, :unauthenticated}
@spec transform_media(Media.t()) :: map()
defp transform_media(%Media{id: id, file: file, metadata: metadata}) do
@spec transform_media(Media.t() | nil) :: map() | nil
def transform_media(nil), do: nil
def transform_media(%Media{id: id, file: file, metadata: metadata}) do
%{
name: file.name,
url: file.url,

View file

@ -381,10 +381,15 @@ defmodule Mobilizon.GraphQL.Resolvers.Participant do
visibility: :private
})
with {:member, true} <-
with {:ok,
%Event{organizer_actor_id: organizer_actor_id, attributed_to_id: attributed_to_id} =
_event} <- Mobilizon.Events.get_event(event_id),
{:member, true} <-
{:member,
to_string(current_actor_id) == to_string(actor_id) or
Actors.member?(current_actor_id, actor_id)},
(to_string(current_actor_id) == to_string(organizer_actor_id) and
to_string(current_actor_id) == to_string(actor_id)) or
(!is_nil(attributed_to_id) and Actors.member?(current_actor_id, attributed_to_id) and
to_string(attributed_to_id) == to_string(actor_id))},
{:ok, _activity, %Conversation{} = conversation} <- Comments.create_conversation(args) do
{:ok, conversation_to_view(conversation, Actors.get_actor(actor_id))}
else

View file

@ -124,6 +124,24 @@ defmodule Mobilizon.GraphQL.Schema.AdminType do
field(:instance_terms_type, :instance_terms_type, description: "The instance's terms type")
field(:instance_terms_url, :string, description: "The instance's terms URL")
field(:instance_logo, :media,
description: "The instance's logo",
resolve: &Admin.get_instance_logo/3
)
field(:instance_favicon, :media,
description: "The instance's favicon",
resolve: &Admin.get_instance_favicon/3
)
field(:default_picture, :media,
description: "The default picture",
resolve: &Admin.get_default_picture/3
)
field(:primary_color, :string, description: "The instance's primary color")
field(:secondary_color, :string, description: "The instance's secondary color")
field(:instance_privacy_policy, :string,
description: "The instance's privacy policy body text"
)
@ -412,6 +430,25 @@ defmodule Mobilizon.GraphQL.Schema.AdminType do
arg(:instance_long_description, :string, description: "The instance's long description")
arg(:instance_slogan, :string, description: "The instance's slogan")
arg(:contact, :string, description: "The instance's contact details")
arg(:instance_logo, :media_input,
description:
"The instance's logo, either as an object or directly the ID of an existing media"
)
arg(:instance_favicon, :media_input,
description:
"The instance's favicon, either as an object or directly the ID of an existing media"
)
arg(:default_picture, :media_input,
description:
"The default picture, either as an object or directly the ID of an existing media"
)
arg(:primary_color, :string, description: "The instance's primary color")
arg(:secondary_color, :string, description: "The instance's secondary color")
arg(:instance_terms, :string, description: "The instance's terms body text")
arg(:instance_terms_type, :instance_terms_type, description: "The instance's terms type")
arg(:instance_terms_url, :string, description: "The instance's terms URL")

View file

@ -31,6 +31,7 @@ defmodule Mobilizon.GraphQL.Schema.ConfigType do
)
field(:demo_mode, :boolean, description: "Whether the demo mode is enabled")
field(:long_events, :boolean, description: "Whether the long events mode is enabled")
field(:country_code, :string, description: "The country code from the IP")
field(:location, :lonlat, description: "The IP's location")
field(:geocoding, :geocoding, description: "The instance's geocoding settings")
@ -59,6 +60,17 @@ defmodule Mobilizon.GraphQL.Schema.ConfigType do
resolve(&Config.terms/3)
end
field(:instance_logo, :media, description: "The instance's logo") do
resolve(&Config.instance_logo/3)
end
field(:default_picture, :media, description: "The default picture") do
resolve(&Config.default_picture/3)
end
field(:primary_color, :string, description: "The instance's primary color")
field(:secondary_color, :string, description: "The instance's secondary color")
field(:privacy, :privacy, description: "The instance's privacy policy") do
arg(:locale, :string,
default_value: "en",

View file

@ -20,6 +20,7 @@ defmodule Mobilizon.GraphQL.Schema.ConversationType do
)
field(:last_comment, :comment, description: "The last comment of the conversation")
field(:origin_comment, :comment, description: "The first comment of the conversation")
field :comments, :paginated_comment_list do
arg(:page, :integer, default_value: 1)

View file

@ -4,7 +4,7 @@ defmodule Mobilizon.GraphQL.Schema.Discussions.CommentType do
"""
use Absinthe.Schema.Notation
import Absinthe.Resolution.Helpers, only: [dataloader: 1]
import Absinthe.Resolution.Helpers, only: [dataloader: 1, dataloader: 2]
alias Mobilizon.{Actors, Discussions, Events}
alias Mobilizon.GraphQL.Resolvers.Comment
@ -23,7 +23,7 @@ defmodule Mobilizon.GraphQL.Schema.Discussions.CommentType do
field(:replies, list_of(:comment)) do
description("A list of replies to the comment")
resolve(dataloader(Discussions))
resolve(dataloader(Discussions, args: %{replies: true}))
end
field(:total_replies, :integer,
@ -47,6 +47,12 @@ defmodule Mobilizon.GraphQL.Schema.Discussions.CommentType do
field(:threadLanguages, non_null(list_of(:string)), description: "The thread languages")
field(:actor, :person, resolve: dataloader(Actors), description: "The comment's author")
field(:attributed_to, :actor,
resolve: dataloader(Actors),
description: "The comment's attributed to actor"
)
field(:inserted_at, :datetime, description: "When was the comment inserted in database")
field(:updated_at, :datetime, description: "When was the comment updated")
field(:deleted_at, :datetime, description: "When was the comment deleted")

View file

@ -263,6 +263,10 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
description: "Whether or not to show the participation price"
)
field(:hide_number_of_participants, :boolean,
description: "Whether or not the number of participants is hidden"
)
field(:show_start_time, :boolean, description: "Show event start time")
field(:show_end_time, :boolean, description: "Show event end time")
@ -316,6 +320,10 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
description: "Whether or not to show the participation price"
)
field(:hide_number_of_participants, :boolean,
description: "Whether or not the number of participants is hidden"
)
field(:show_start_time, :boolean, description: "Show event start time")
field(:show_end_time, :boolean, description: "Show event end time")
@ -367,6 +375,13 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
object :event_queries do
@desc "Get all events"
field :events, :paginated_event_list do
arg(:location, :string, default_value: nil, description: "A geohash for coordinates")
arg(:radius, :float,
default_value: nil,
description: "Radius around the location to search in"
)
arg(:page, :integer, default_value: 1, description: "The page in the paginated event list")
arg(:limit, :integer, default_value: 10, description: "The limit of events per page")
@ -380,6 +395,11 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
description: "Direction for the sort"
)
arg(:longevents, :boolean,
default_value: nil,
description: "if mention filter in or out long events"
)
middleware(Rajska.QueryAuthorization, permit: :all)
resolve(&Event.list_events/3)

View file

@ -52,8 +52,9 @@ defmodule Mobilizon.GraphQL.Schema.MediaType do
input_object :media_input_object do
field(:name, non_null(:string), description: "The media's name")
field(:alt, :string, description: "The media's alternative text")
field(:file, non_null(:upload), description: "The media file")
field(:file, :upload, description: "The media file")
field(:actor_id, :id, description: "The media owner")
field(:url, :string, description: "The media URL")
end
object :media_queries do

View file

@ -160,6 +160,8 @@ defmodule Mobilizon.GraphQL.Schema.SearchType do
end
enum :search_target do
value(:self, description: "Search only on content from this instance")
value(:internal,
description: "Search on content from this instance and from the followed instances"
)
@ -271,6 +273,8 @@ defmodule Mobilizon.GraphQL.Schema.SearchType do
description: "Radius around the location to search in"
)
arg(:longevents, :boolean, description: "if mention filter in or out long events")
arg(:bbox, :string, description: "The bbox to search events into")
arg(:zoom, :integer, description: "The zoom level for searching events")

View file

@ -85,7 +85,9 @@ defmodule Mobilizon do
ErrorReporting.attach()
end
Supervisor.start_link(children, strategy: :one_for_one, name: Mobilizon.Supervisor)
with :ok <- load_certificates() do
Supervisor.start_link(children, strategy: :one_for_one, name: Mobilizon.Supervisor)
end
end
@spec config_change(keyword, keyword, [atom]) :: :ok
@ -160,4 +162,16 @@ defmodule Mobilizon do
end
defp setup_ecto_dev_logger(_), do: nil
defp load_certificates do
custom_cert_path = System.get_env("MOBILIZON_CA_CERT_PATH")
if is_binary(custom_cert_path) do
with :ok <- :tls_certificate_check.override_trusted_authorities({:file, custom_cert_path}) do
:public_key.cacerts_load(custom_cert_path)
end
else
:ok
end
end
end

View file

@ -525,6 +525,7 @@ defmodule Mobilizon.Actors do
Keyword.get(options, :radius),
Keyword.get(options, :bbox)
)
|> filter_by_local_only(Keyword.get(options, :local_only, false))
|> actors_for_location(Keyword.get(options, :location), Keyword.get(options, :radius))
|> events_for_bounding_box(Keyword.get(options, :bbox))
|> filter_by_type(Keyword.get(options, :actor_type, :Group))
@ -1418,6 +1419,13 @@ defmodule Mobilizon.Actors do
defp maybe_join_address(query, _location, _radius, _bbox), do: query
@spec filter_by_local_only(Ecto.Queryable.t(), boolean()) :: Ecto.Query.t()
defp filter_by_local_only(query, true) do
where(query, [q], is_nil(q.domain))
end
defp filter_by_local_only(query, false), do: query
@spec actors_for_location(Ecto.Queryable.t(), String.t(), integer()) :: Ecto.Query.t()
defp actors_for_location(query, location, radius)
when is_valid_string(location) and not is_nil(radius) do

View file

@ -9,7 +9,8 @@ defmodule Mobilizon.Admin do
alias Mobilizon.Actors.Actor
alias Mobilizon.{Admin, Users}
alias Mobilizon.Admin.ActionLog
alias Mobilizon.Admin.Setting
alias Mobilizon.Admin.{Setting, SettingMedia}
alias Mobilizon.Medias.Media
alias Mobilizon.Storage.{Page, Repo}
alias Mobilizon.Users.User
@ -78,9 +79,47 @@ defmodule Mobilizon.Admin do
defp stringify_struct(struct), do: struct
@spec get_all_admin_settings :: list(Setting.t())
@spec get_all_admin_settings :: map()
def get_all_admin_settings do
Repo.all(Setting)
medias =
SettingMedia
|> Repo.all()
|> Repo.preload(:media)
|> Enum.map(fn %SettingMedia{group: group, name: name, media: media} ->
{group, name, media}
end)
values =
Setting
|> Repo.all()
|> Enum.map(fn %Setting{group: group, name: name, value: value} ->
{group, name, get_setting_value(value)}
end)
all_settings = Enum.concat(values, medias)
Enum.reduce(
all_settings,
%{},
# For each {group,name,value}
fn {group, name, value}, acc ->
# We update the %{group: map} in the accumulator
{_, new_acc} =
Map.get_and_update(
acc,
group,
# We put the %{name: value} into the %{group: map}
fn group_map ->
{
group_map,
Map.put(group_map || %{}, name, value)
}
end
)
new_acc
end
)
end
@spec get_admin_setting_value(String.t(), String.t(), String.t() | nil) ::
@ -119,21 +158,40 @@ defmodule Mobilizon.Admin do
end
end
@spec get_admin_setting_media(String.t(), String.t(), String.t() | nil) ::
{:ok, Media.t()} | {:error, :not_found} | nil
def get_admin_setting_media(group, name, fallback \\ nil)
when is_binary(group) and is_binary(name) do
case SettingMedia
|> where(group: ^group)
|> where(name: ^name)
|> preload(:media)
|> Repo.one() do
nil ->
fallback
%SettingMedia{media: media} ->
media
%SettingMedia{} ->
fallback
end
end
@spec save_settings(String.t(), map()) :: {:ok, any} | {:error, any}
def save_settings(group, args) do
{medias, values} = Map.split(args, [:instance_logo, :instance_favicon, :default_picture])
Multi.new()
|> do_save_setting(group, args)
|> do_save_media_setting(group, medias)
|> do_save_value_setting(group, values)
|> Repo.transaction()
end
def clear_settings(group) do
Setting |> where([s], s.group == ^group) |> Repo.delete_all()
end
@spec do_save_value_setting(Ecto.Multi.t(), String.t(), map()) :: Ecto.Multi.t()
defp do_save_value_setting(transaction, _group, args) when args == %{}, do: transaction
@spec do_save_setting(Ecto.Multi.t(), String.t(), map()) :: Ecto.Multi.t()
defp do_save_setting(transaction, _group, args) when args == %{}, do: transaction
defp do_save_setting(transaction, group, args) do
defp do_save_value_setting(transaction, group, args) do
key = hd(Map.keys(args))
{val, rest} = Map.pop(args, key)
@ -150,7 +208,40 @@ defmodule Mobilizon.Admin do
conflict_target: [:group, :name]
)
do_save_setting(transaction, group, rest)
do_save_value_setting(transaction, group, rest)
end
@spec do_save_media_setting(Ecto.Multi.t(), String.t(), map()) :: Ecto.Multi.t()
defp do_save_media_setting(transaction, _group, args) when args == %{}, do: transaction
defp do_save_media_setting(transaction, group, args) do
key = hd(Map.keys(args))
{val, rest} = Map.pop(args, key)
transaction =
case val do
val ->
Multi.insert(
transaction,
key,
SettingMedia.changeset(%SettingMedia{}, %{
group: group,
name: Atom.to_string(key),
media: val
}),
on_conflict: :replace_all,
conflict_target: [:group, :name]
)
end
do_save_media_setting(transaction, group, rest)
end
def clear_settings(group) do
Multi.new()
|> Multi.delete_all(:settings, Setting |> where([s], s.group == ^group))
|> Multi.delete_all(:settings_medias, SettingMedia |> where([s], s.group == ^group))
|> Repo.transaction()
end
@spec convert_to_string(any()) :: String.t()

View file

@ -4,6 +4,7 @@ defmodule Mobilizon.Admin.Setting do
"""
use Ecto.Schema
import Ecto.Changeset
alias Ecto.Changeset
@required_attrs [:group, :name]
@optional_attrs [:value]
@ -32,3 +33,93 @@ defmodule Mobilizon.Admin.Setting do
|> unique_constraint(:group, name: :admin_settings_group_name_index)
end
end
defmodule Mobilizon.Admin.SettingMedia do
@moduledoc """
A Key-Value settings table for media settings
"""
use Ecto.Schema
import Ecto.Changeset
alias Ecto.Changeset
alias Mobilizon.Federation.ActivityPub.Relay
alias Mobilizon.Medias
alias Mobilizon.Medias.Media
alias Mobilizon.Storage.Repo
@required_attrs [:group, :name]
@type t :: %{
group: String.t(),
name: String.t(),
media: Media.t()
}
schema "admin_settings_medias" do
field(:group, :string)
field(:name, :string)
belongs_to(:media, Media, on_replace: :delete)
timestamps()
end
@doc false
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(setting_media, attrs) do
setting_media
|> Repo.preload(:media)
|> cast(attrs, @required_attrs)
|> put_media(attrs)
|> validate_required(@required_attrs)
|> unique_constraint(:group, name: :admin_settings_medias_group_name_index)
end
# # In case the provided media is an existing one
@spec put_media(Changeset.t(), map) :: Changeset.t()
defp put_media(%Changeset{} = changeset, %{media: %{media_id: id}}) do
%Media{} = media = Medias.get_media!(id)
put_assoc(changeset, :media, media)
end
# In case it's a new media
defp put_media(%Changeset{} = changeset, %{media: %{media: media}}) do
{:ok, media} = upload_media(media)
put_assoc(changeset, :media, media)
end
# In case there is no media
defp put_media(%Changeset{} = changeset, _media) do
put_assoc(changeset, :media, nil)
end
import Mobilizon.Web.Gettext
@spec upload_media(map) :: {:ok, Media.t()} | {:error, any}
defp upload_media(%{file: %Plug.Upload{} = file} = args) do
with {:ok,
%{
name: _name,
url: url,
content_type: content_type,
size: size
} = uploaded} <-
Mobilizon.Web.Upload.store(file),
args <-
args
|> Map.put(:url, url)
|> Map.put(:size, size)
|> Map.put(:content_type, content_type),
{:ok, media = %Media{}} <-
Medias.create_media(%{
file: args,
actor_id: Map.get(args, :actor_id, Relay.get_actor().id),
metadata: Map.take(uploaded, [:width, :height, :blurhash])
}) do
{:ok, media}
else
{:error, :mime_type_not_allowed} ->
{:error, dgettext("errors", "File doesn't have an allowed MIME type.")}
error ->
{:error, error}
end
end
end

View file

@ -4,7 +4,8 @@ defmodule Mobilizon.Config do
"""
alias Mobilizon.Actors
alias Mobilizon.Admin.Setting
alias Mobilizon.Admin
alias Mobilizon.Medias.Media
alias Mobilizon.Service.GitStatus
require Logger
import Mobilizon.Service.Export.Participants.Common, only: [enabled_formats: 0]
@ -30,56 +31,18 @@ defmodule Mobilizon.Config do
@spec instance_config :: mobilizon_config
def instance_config, do: Application.get_env(:mobilizon, :instance)
@spec db_instance_config :: list(Setting.t())
def db_instance_config, do: Mobilizon.Admin.get_all_admin_settings()
@spec config_cache :: map()
def config_cache do
case Cachex.fetch(:config, :all_db_config, fn _key ->
value =
Enum.reduce(
Mobilizon.Admin.get_all_admin_settings(),
%{},
&arrange_values/2
)
{:commit, value}
end) do
case Cachex.fetch(
:config,
:all_db_config,
fn _key -> {:commit, Admin.get_all_admin_settings()} end
) do
{status, value} when status in [:ok, :commit] -> value
_err -> %{}
end
end
@spec arrange_values(Setting.t(), map()) :: map()
defp arrange_values(setting, acc) do
{_, new_data} =
Map.get_and_update(acc, setting.group, fn current_value ->
new_value = current_value || %{}
{current_value, Map.put(new_value, setting.name, process_value(setting.value))}
end)
new_data
end
@spec process_value(String.t() | nil) :: any()
defp process_value(nil), do: nil
defp process_value(""), do: nil
defp process_value(value) do
case Jason.decode(value) do
{:ok, val} ->
val
{:error, _} ->
case value do
"true" -> true
"false" -> false
value -> value
end
end
end
@spec config_cached_value(String.t(), String.t(), String.t()) :: any()
def config_cached_value(group, name, fallback \\ nil) do
config_cache()
@ -116,10 +79,23 @@ defmodule Mobilizon.Config do
@spec instance_slogan :: String.t() | nil
def instance_slogan, do: config_cached_value("instance", "instance_slogan")
@spec instance_logo :: Media.t() | nil
def instance_logo, do: config_cached_value("instance", "instance_logo")
@spec instance_favicon :: Media.t() | nil
def instance_favicon, do: config_cached_value("instance", "instance_favicon")
@spec default_picture :: Media.t() | nil
def default_picture, do: config_cached_value("instance", "default_picture")
@spec primary_color :: Media.t() | nil
def primary_color, do: config_cached_value("instance", "primary_color")
@spec secondary_color :: Media.t() | nil
def secondary_color, do: config_cached_value("instance", "secondary_color")
@spec contact :: String.t() | nil
def contact do
config_cached_value("instance", "contact")
end
def contact, do: config_cached_value("instance", "contact")
@spec instance_terms(String.t()) :: String.t()
def instance_terms(locale \\ "en") do
@ -201,6 +177,9 @@ defmodule Mobilizon.Config do
@spec instance_demo_mode? :: boolean
def instance_demo_mode?, do: to_boolean(instance_config()[:demo])
@spec instance_long_events? :: boolean
def instance_long_events?, do: instance_config()[:duration_of_long_event] > 0
@spec instance_repository :: String.t()
def instance_repository, do: instance_config()[:repository]
@ -469,6 +448,9 @@ defmodule Mobilizon.Config do
instance_slogan: instance_slogan(),
registrations_open: instance_registrations_open?(),
contact: contact(),
primary_color: primary_color(),
secondary_color: secondary_color(),
instance_logo: instance_logo(),
instance_terms: instance_terms(),
instance_terms_type: instance_terms_type(),
instance_terms_url: instance_terms_url(),

View file

@ -104,6 +104,10 @@ defmodule Mobilizon.Conversations do
|> join(:inner, [_cp, _c, _e, _a, _lc, _oc, p], ap in Actor, on: p.actor_id == ap.id)
|> where([_cp, c], c.event_id == ^event_id)
|> where([cp], cp.actor_id == ^actor_id)
|> where(
[_cp, _c, _e, _a, _lc, oc],
oc.actor_id == ^actor_id or oc.attributed_to_id == ^actor_id
)
|> order_by([cp], desc: cp.unread, desc: cp.updated_at)
|> preload([_cp, c, e, a, lc, oc, p, ap],
actor: a,
@ -113,6 +117,14 @@ defmodule Mobilizon.Conversations do
|> Page.build_page(page, limit)
end
def find_all_conversations_for_event(event_id) do
ConversationParticipant
|> join(:inner, [cp], c in Conversation, on: cp.conversation_id == c.id)
|> join(:left, [_cp, c], e in Event, on: c.event_id == e.id)
|> where([_cp, c], c.event_id == ^event_id)
|> Repo.all()
end
@spec list_conversation_participants_for_actor(
integer | String.t(),
integer | nil,
@ -133,7 +145,7 @@ defmodule Mobilizon.Conversations do
subquery
|> subquery()
|> order_by([cp], desc: cp.unread, desc: cp.updated_at)
|> preload([:actor, conversation: [:last_comment, :participants]])
|> preload([:actor, conversation: [:last_comment, :origin_comment, :participants, :event]])
|> Page.build_page(page, limit)
end
@ -147,7 +159,7 @@ defmodule Mobilizon.Conversations do
ConversationParticipant
|> join(:inner, [cp], a in Actor, on: cp.actor_id == a.id)
|> where([_cp, a], a.user_id == ^user_id)
|> preload([:actor, conversation: [:last_comment, :participants]])
|> preload([:actor, conversation: [:last_comment, :origin_comment, :participants, :event]])
|> Page.build_page(page, limit)
end

View file

@ -85,6 +85,13 @@ defmodule Mobilizon.Discussions do
|> select([c, r], %{c | total_replies: count(r.id)})
end
# Replies are only used on event comments, so we always use public visibily here
def query(Comment, %{replies: true}) do
Comment
|> where([c], c.visibility in ^@public_visibility)
|> order_by([c], asc: :is_announcement, asc: :published_at)
end
def query(Comment, _) do
order_by(Comment, [c], asc: :is_announcement, asc: :published_at)
end

View file

@ -25,6 +25,7 @@ defmodule Mobilizon.Events.EventOptions do
show_participation_price: boolean,
offers: [EventOffer.t()],
participation_condition: [EventParticipationCondition.t()],
hide_number_of_participants: boolean,
show_start_time: boolean,
show_end_time: boolean,
timezone: String.t() | nil,
@ -41,6 +42,7 @@ defmodule Mobilizon.Events.EventOptions do
:program,
:comment_moderation,
:show_participation_price,
:hide_number_of_participants,
:show_start_time,
:show_end_time,
:timezone,
@ -59,6 +61,7 @@ defmodule Mobilizon.Events.EventOptions do
field(:program, :string)
field(:comment_moderation, CommentModeration)
field(:show_participation_price, :boolean)
field(:hide_number_of_participants, :boolean, default: false)
field(:show_start_time, :boolean, default: true)
field(:show_end_time, :boolean, default: true)
field(:timezone, :string)

View file

@ -16,6 +16,7 @@ defmodule Mobilizon.Events do
alias Mobilizon.Actors.{Actor, Follower}
alias Mobilizon.Addresses.Address
alias Mobilizon.Config
alias Mobilizon.Events.{
Event,
@ -358,19 +359,34 @@ defmodule Mobilizon.Events do
@doc """
Returns the list of events.
"""
@spec list_events(integer | nil, integer | nil, atom, atom, boolean) :: Page.t(Event.t())
@spec list_events(
integer | nil,
integer | nil,
atom,
atom,
boolean,
boolean | nil,
string | nil,
float | nil
) :: Page.t(Event.t())
def list_events(
page \\ nil,
limit \\ nil,
sort \\ :begins_on,
direction \\ :asc,
is_future \\ true
is_future \\ true,
longevents \\ nil,
location \\ nil,
radius \\ nil
) do
Event
|> distinct([e], [{^direction, ^sort}, asc: e.id])
|> preload([:organizer_actor, :participants])
|> sort(sort, direction)
|> maybe_join_address(%{location: location, radius: radius})
|> events_for_location(%{location: location, radius: radius})
|> filter_future_events(is_future)
|> events_for_longevents(longevents)
|> filter_public_visibility()
|> filter_draft()
|> filter_cancelled_events()
@ -571,6 +587,7 @@ defmodule Mobilizon.Events do
|> events_for_search_query()
|> events_for_begins_on(Map.get(args, :begins_on, DateTime.utc_now()))
|> events_for_ends_on(Map.get(args, :ends_on))
|> events_for_longevents(Map.get(args, :longevents))
|> events_for_category(args)
|> events_for_categories(args)
|> events_for_languages(args)
@ -581,6 +598,7 @@ defmodule Mobilizon.Events do
|> events_for_bounding_box(args)
|> filter_online(args)
|> filter_draft()
|> filter_local(if Map.get(args, :local_only, nil) == true, do: true, else: nil)
|> filter_local_or_from_followed_instances_events()
|> filter_public_visibility()
|> event_order(Map.get(args, :sort_by, :match_desc), search_string)
@ -792,7 +810,7 @@ defmodule Mobilizon.Events do
end
end
def get_participant(event_id, actor_id, %{}) do
def get_participant(event_id, actor_id, _params) do
case Participant
|> Repo.get_by(event_id: event_id, actor_id: actor_id)
|> Repo.preload(@participant_preloads) do
@ -1376,6 +1394,36 @@ defmodule Mobilizon.Events do
end
end
@spec events_for_longevents(Ecto.Queryable.t(), Boolean.t() | nil) :: Ecto.Query.t()
defp events_for_longevents(query, longevents) do
duration = Config.get([:instance, :duration_of_long_event], 0)
if duration <= 0 do
query
else
case longevents do
nil ->
query
true ->
where(
query,
[q],
not is_nil(q.ends_on) and
q.ends_on > fragment("? + '1 days'::interval * ?", q.begins_on, ^duration)
)
false ->
where(
query,
[q],
is_nil(q.ends_on) or
q.ends_on <= fragment("? + '1 days'::interval * ?", q.begins_on, ^duration)
)
end
end
end
@spec events_for_category(Ecto.Queryable.t(), map()) :: Ecto.Query.t()
defp events_for_category(query, %{category: category}) when is_valid_string(category) do
where(query, [q], q.category == ^category)
@ -1774,6 +1822,7 @@ defmodule Mobilizon.Events do
|> distinct([e], e.id)
|> join(:left, [e], et in "events_tags", on: e.id == et.event_id)
|> join(:left, [e], a in Address, on: e.physical_address_id == a.id)
|> filter_future_events(true)
|> filter_draft()
|> filter_local_or_from_followed_instances_events()
|> filter_public_visibility()

View file

@ -185,7 +185,8 @@ defmodule Mobilizon.Medias do
[from: "events_medias", param: "media_id"],
[from: "posts", param: "picture_id"],
[from: "posts_medias", param: "media_id"],
[from: "comments_medias", param: "media_id"]
[from: "comments_medias", param: "media_id"],
[from: "admin_settings_medias", param: "media_id"]
]
|> Enum.map_join(" UNION ", fn [from: from, param: param] ->
"SELECT 1 FROM #{from} WHERE #{from}.#{param} = m0.id"

View file

@ -2,7 +2,7 @@ defmodule Mobilizon.Service.Activity.Conversation do
@moduledoc """
Insert a conversation activity
"""
alias Mobilizon.Conversations
alias Mobilizon.{Actors, Conversations}
alias Mobilizon.Conversations.{Conversation, ConversationParticipant}
alias Mobilizon.Discussions.Comment
alias Mobilizon.Events.Event
@ -38,7 +38,7 @@ defmodule Mobilizon.Service.Activity.Conversation do
%Conversation{
id: conversation_id
} = conversation,
%Comment{actor_id: actor_id, text: last_comment_text},
%Comment{actor_id: actor_id, text: last_comment_text} = comment,
_options
)
when subject in [
@ -55,7 +55,8 @@ defmodule Mobilizon.Service.Activity.Conversation do
actor_id: conversation_participant_actor_id
} =
conversation_participant ->
if actor_id != conversation_participant_actor_id do
if actor_id != conversation_participant_actor_id and
can_send_event_announcement?(conversation, comment) do
LegacyNotifierBuilder.enqueue(
:legacy_notify,
%{
@ -98,4 +99,31 @@ defmodule Mobilizon.Service.Activity.Conversation do
}
defp event_subject_params(_), do: %{}
@spec can_send_event_announcement?(Conversation.t(), Comment.t()) :: boolean()
defp can_send_event_announcement?(
%Conversation{
event: %Event{
attributed_to_id: attributed_to_id
}
},
%Comment{actor_id: actor_id}
)
when not is_nil(attributed_to_id) do
attributed_to_id == actor_id or Actors.member?(actor_id, attributed_to_id)
end
defp can_send_event_announcement?(
%Conversation{
event: %Event{
organizer_actor_id: organizer_actor_id
}
},
%Comment{actor_id: actor_id}
)
when not is_nil(organizer_actor_id) do
organizer_actor_id == actor_id
end
defp can_send_event_announcement?(_, _), do: false
end

View file

@ -85,7 +85,7 @@ defmodule Mobilizon.Service.Address do
defined?(street) ->
if defined?(locality), do: "#{street} (#{locality})", else: street
defined?(locality) ->
defined?(locality) and locality != region ->
"#{locality}, #{region}, #{country}"
defined?(region) ->

View file

@ -0,0 +1,12 @@
defmodule Mobilizon.Service.Config.Helpers do
@moduledoc """
Provide some helpers to configuration files
"""
@spec host_from_uri(String.t() | nil) :: String.t() | nil
def host_from_uri(nil), do: nil
def host_from_uri(uri) when is_binary(uri) do
URI.parse(uri).host
end
end

View file

@ -0,0 +1,43 @@
defmodule Mobilizon.Service.Geospatial.Hat do
@moduledoc """
Hat backend.
"""
alias Mobilizon.Addresses.Address
alias Mobilizon.Service.Geospatial.Addok
alias Mobilizon.Service.Geospatial.Nominatim
alias Mobilizon.Service.Geospatial.Provider
require Logger
@behaviour Provider
@impl Provider
@doc """
Hat implementation for `c:Mobilizon.Service.Geospatial.Provider.geocode/3`.
"""
@spec geocode(String.t(), keyword()) :: list(Address.t())
def geocode(lon, lat, options \\ []) do
tasks = [
Task.async(fn -> Addok.geocode(lon, lat, options) end),
Task.async(fn -> Nominatim.geocode(lon, lat, options) end)
]
[addrlist1, addrlist2] = Task.await_many(tasks, 12_000)
addrlist2 ++ addrlist1
end
@impl Provider
@doc """
Hat implementation for `c:Mobilizon.Service.Geospatial.Provider.search/2`.
"""
@spec search(String.t(), keyword()) :: list(Address.t())
def search(q, options \\ []) do
tasks = [
Task.async(fn -> Addok.search(q, options) end),
Task.async(fn -> Nominatim.search(q, options) end)
]
[addrlist1, addrlist2] = Task.await_many(tasks, 12_000)
addrlist2 ++ addrlist1
end
end

View file

@ -3,7 +3,9 @@ defmodule Mobilizon.Service.HTTP.ActivityPub do
Tesla HTTP Client that is preconfigured to get and post ActivityPub content
"""
require Logger
alias Mobilizon.Config
import Mobilizon.Service.HTTP.Utils, only: [get_tls_config: 0]
@default_opts [
recv_timeout: 20_000
@ -13,7 +15,11 @@ defmodule Mobilizon.Service.HTTP.ActivityPub do
def client(options \\ []) do
headers = Keyword.get(options, :headers, [])
adapter = Application.get_env(:tesla, __MODULE__, [])[:adapter] || Tesla.Adapter.Hackney
opts = Keyword.merge(@default_opts, Keyword.get(options, :opts, []))
opts =
@default_opts
|> Keyword.merge(ssl_options: get_tls_config())
|> Keyword.merge(Keyword.get(options, :opts, []))
middleware = [
{Tesla.Middleware.Headers,

View file

@ -4,6 +4,7 @@ defmodule Mobilizon.Service.HTTP.GenericJSONClient do
"""
alias Mobilizon.Config
import Mobilizon.Service.HTTP.Utils, only: [get_tls_config: 0]
@default_opts [
recv_timeout: 20_000
@ -13,7 +14,11 @@ defmodule Mobilizon.Service.HTTP.GenericJSONClient do
def client(options \\ []) do
headers = Keyword.get(options, :headers, [])
adapter = Application.get_env(:tesla, __MODULE__, [])[:adapter] || Tesla.Adapter.Hackney
opts = Keyword.merge(@default_opts, Keyword.get(options, :opts, []))
opts =
@default_opts
|> Keyword.merge(ssl_options: get_tls_config())
|> Keyword.merge(Keyword.get(options, :opts, []))
middleware = [
{Tesla.Middleware.Headers,

View file

@ -6,12 +6,13 @@ defmodule Mobilizon.Service.HTTP.GeospatialClient do
use Tesla
alias Mobilizon.Config
import Mobilizon.Service.HTTP.Utils, only: [get_tls_config: 0]
@default_opts [
recv_timeout: 20_000
]
adapter(Tesla.Adapter.Hackney, @default_opts)
adapter(Tesla.Adapter.Hackney, Keyword.merge([ssl_options: get_tls_config()], @default_opts))
plug(Tesla.Middleware.FollowRedirects)

View file

@ -6,12 +6,13 @@ defmodule Mobilizon.Service.HTTP.HostMetaClient do
use Tesla
alias Mobilizon.Config
import Mobilizon.Service.HTTP.Utils, only: [get_tls_config: 0]
@default_opts [
recv_timeout: 20_000
]
adapter(Tesla.Adapter.Hackney, @default_opts)
adapter(Tesla.Adapter.Hackney, Keyword.merge([ssl_options: get_tls_config()], @default_opts))
plug(Tesla.Middleware.FollowRedirects)

View file

@ -5,12 +5,13 @@ defmodule Mobilizon.Service.HTTP.RemoteMediaDownloaderClient do
use Tesla
alias Mobilizon.Config
import Mobilizon.Service.HTTP.Utils, only: [get_tls_config: 0]
@default_opts [
recv_timeout: 20_000
]
adapter(Tesla.Adapter.Hackney, @default_opts)
adapter(Tesla.Adapter.Hackney, Keyword.merge([ssl_options: get_tls_config()], @default_opts))
plug(Tesla.Middleware.FollowRedirects)

View file

@ -5,12 +5,13 @@ defmodule Mobilizon.Service.HTTP.RichMediaPreviewClient do
use Tesla
alias Mobilizon.Config
import Mobilizon.Service.HTTP.Utils, only: [get_tls_config: 0]
@default_opts [
recv_timeout: 20_000
]
adapter(Tesla.Adapter.Hackney, @default_opts)
adapter(Tesla.Adapter.Hackney, Keyword.merge([ssl_options: get_tls_config()], @default_opts))
plug(Tesla.Middleware.FollowRedirects)

View file

@ -3,6 +3,17 @@ defmodule Mobilizon.Service.HTTP.Utils do
Utils for HTTP operations
"""
def get_tls_config do
cacertfile =
if is_nil(System.get_env("MOBILIZON_CA_CERT_PATH")) do
CAStore.file_path()
else
System.get_env("MOBILIZON_CA_CERT_PATH")
end
[cacertfile: cacertfile]
end
@spec get_header(Enum.t(), String.t()) :: String.t() | nil
def get_header(headers, key) do
key = String.downcase(key)

View file

@ -6,12 +6,13 @@ defmodule Mobilizon.Service.HTTP.WebfingerClient do
use Tesla
alias Mobilizon.Config
import Mobilizon.Service.HTTP.Utils, only: [get_tls_config: 0]
@default_opts [
recv_timeout: 20_000
]
adapter(Tesla.Adapter.Hackney, @default_opts)
adapter(Tesla.Adapter.Hackney, Keyword.merge([ssl_options: get_tls_config()], @default_opts))
plug(Tesla.Middleware.FollowRedirects)

View file

@ -136,14 +136,12 @@ defimpl Mobilizon.Service.Metadata, for: Mobilizon.Events.Event do
defp build_language(language, locale), do: language || locale
@spec build_begins_on(DateTime.t(), String.t() | nil) :: DateTime.t()
defp build_begins_on(begins_on, nil), do: begins_on
defp build_begins_on(begins_on, timezone) do
if timezone do
case DateTime.shift_zone(begins_on, timezone) do
{:ok, begins_on} -> begins_on
{:error, _err} -> begins_on
end
else
begins_on
case DateTime.shift_zone(begins_on, timezone) do
{:ok, begins_on} -> begins_on
{:error, _err} -> begins_on
end
end

View file

@ -56,7 +56,6 @@ defmodule Mobilizon.Service.SiteMap do
end)
|> Sitemapper.generate(config)
|> Sitemapper.persist(config)
|> Sitemapper.ping(config)
|> Stream.run()
end,
timeout: :infinity

View file

@ -4,7 +4,7 @@ defmodule Mobilizon.Service.Workers.LegacyNotifierBuilder do
"""
alias Mobilizon.Activities.Activity
alias Mobilizon.{Actors, Events, Users}
alias Mobilizon.{Actors, Config, Events, Users}
alias Mobilizon.Actors.Actor
alias Mobilizon.Events.{Event, Participant}
alias Mobilizon.Service.Notifier
@ -37,9 +37,10 @@ defmodule Mobilizon.Service.Workers.LegacyNotifierBuilder do
end
defp special_handling("conversation_created", args, activity) do
notify_participants(
notify_participant(
get_in(args, ["subject_params", "conversation_event_id"]),
activity,
get_in(args, ["participant", "actor_id"]),
args["author_id"]
)
end
@ -143,6 +144,24 @@ defmodule Mobilizon.Service.Workers.LegacyNotifierBuilder do
notify_anonymous_participants(event_id, activity)
end
defp notify_participant(nil, _activity, _conversation_participant_actor_id, _author_id),
do: :ok
defp notify_participant(event_id, activity, conversation_participant_actor_id, author_id) do
# Anonymous participation
if conversation_participant_actor_id == Config.anonymous_actor_id() do
notify_anonymous_participants(event_id, activity)
else
[conversation_participant_actor_id]
|> users_from_actor_ids(author_id)
|> Enum.each(fn user ->
Notifier.Email.send_anonymous_activity(user.email, activity,
locale: Map.get(user, :locale, "en")
)
end)
end
end
defp notify_anonymous_participants(nil, _activity), do: :ok
defp notify_anonymous_participants(event_id, activity) do
@ -154,7 +173,7 @@ defmodule Mobilizon.Service.Workers.LegacyNotifierBuilder do
|> Enum.map(fn %Participant{metadata: metadata} -> metadata end)
|> Enum.map(fn %{email: email} = metadata ->
Notifier.Email.send_anonymous_activity(email, activity,
locale: Map.get(metadata, :locale, "en")
locale: Map.get(metadata, :locale, "en") || "en"
)
end)
end

View file

@ -0,0 +1,58 @@
defmodule Mobilizon.Web.ManifestController do
use Mobilizon.Web, :controller
alias Mobilizon.Config
alias Mobilizon.Medias.Media
@spec manifest(Plug.Conn.t(), any) :: Plug.Conn.t()
def manifest(conn, _params) do
favicons =
case Config.instance_favicon() do
%Media{file: %{url: url}, metadata: metadata} ->
[
Map.merge(
%{
src: url
},
case metadata do
%{width: width} -> %{sizes: "#{width}x#{width}"}
_ -> %{}
end
)
]
_ ->
[
%{
src: "./img/icons/android-chrome-512x512.png",
sizes: "512x512",
type: "image/png"
},
%{
src: "./img/icons/android-chrome-192x192.png",
sizes: "192x192",
type: "image/png"
}
]
end
json(conn, %{
name: Config.instance_name(),
start_url: "/",
scope: "/",
display: "standalone",
background_color: "#ffffff",
theme_color: "#ffd599",
orientation: "portrait-primary",
icons: favicons
})
end
@spec favicon(Plug.Conn.t(), any) :: Plug.Conn.t()
def favicon(conn, _params) do
case Config.instance_favicon() do
%Media{file: %{url: url}} -> redirect(conn, external: url)
_ -> redirect(conn, to: "/img/icons/favicon.ico")
end
end
end

View file

@ -18,8 +18,7 @@ defmodule Mobilizon.Web do
"""
def static_paths,
do:
~w(index.html manifest.json manifest.webmanifest service-worker.js css fonts img js favicon.ico robots.txt assets)
do: ~w(index.html service-worker.js css fonts img js robots.txt assets)
def controller do
quote do

View file

@ -95,7 +95,7 @@ defmodule Mobilizon.Web.Router do
forward("/", Absinthe.Plug,
schema: Mobilizon.GraphQL.Schema,
analyze_complexity: true,
max_complexity: 250
max_complexity: 300
)
end
@ -113,6 +113,12 @@ defmodule Mobilizon.Web.Router do
get("/nodeinfo/:version", NodeInfoController, :nodeinfo)
end
scope "/", Mobilizon.Web do
get("/manifest.webmanifest", ManifestController, :manifest)
get("/manifest.json", ManifestController, :manifest)
get("/favicon.ico", ManifestController, :favicon)
end
scope "/", Mobilizon.Web do
pipe_through(:activity_pub_and_html)
pipe_through(:activity_pub_signature)

View file

@ -54,7 +54,7 @@
<p>
<%= pgettext(
"terms",
"When we say “we”, “our”, or “us” in this document, we are referring to the owners, operators and administrators of this Mobilizon instance. The Mobilizon software is provided by the team of Mobilizon contributors, supported by <a href=\"https://framasoft.org\">Framasoft</a>, a French not-for-profit organization advocating for Free/Libre Software. Unless explicitly stated, this Mobilizon instance is an independent service using Mobilizon's source code. You may find more information about this instance on the <a href=\"/about/instance\">\"About this instance\"</a> page."
"When we say “we”, “our”, or “us” in this document, we are referring to the owners, operators and administrators of this Mobilizon instance. The Mobilizon software is provided by the team of Mobilizon contributors. Unless explicitly stated, this Mobilizon instance is an independent service using Mobilizon's source code. You may find more information about this instance on the <a href=\"/about/instance\">\"About this instance\"</a> page."
)
|> raw %>
</p>

View file

@ -7,4 +7,4 @@
<%= if @follower.type == :Application do %><%= gettext "Note: %{name} following you doesn't necessarily imply that you follow this instance, but you can ask to follow them too.", name: Mobilizon.Actors.Actor.display_name_and_username(@follower) %><% end %>
<%= if @follower.type == :Application do %><%= gettext "To accept this invitation, head over to the instance's admin settings." %><% else %><%= gettext "To accept this invitation, head over to the profile's admin page." %><% end %>
<%= if @follower.type == :Application do %><%= "#{Mobilizon.Web.Endpoint.url()}/settings/admin/instances/%{name}" %><% else %><%= "#{Mobilizon.Web.Endpoint.url()}/settings/admin/profiles/#{@follower.id}" %><% end %>
<%= if @follower.type == :Application do %><%= "#{Mobilizon.Web.Endpoint.url()}/settings/admin/instances/#{@follower.domain}" %><% else %><%= "#{Mobilizon.Web.Endpoint.url()}/settings/admin/profiles/#{@follower.id}" %><% end %>

View file

@ -4,26 +4,23 @@
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="apple-touch-icon" href="/img/icons/apple-touch-icon-152x152.png" sizes="152x152" />
<link rel="apple-touch-icon" href={favicon_url()} sizes={favicon_sizes()} />
<link rel="icon" href={favicon_url()} sizes={favicon_sizes()} />
<link rel="mask-icon" href="/img/icons/safari-pinned-tab.svg" color={theme_color()} />
<link rel="manifest" href="/manifest.webmanifest" />
<meta name="theme-color" content={theme_color()} />
<script>
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark')
document.documentElement.classList.add('dark')
} else {
document.documentElement.classList.remove('dark')
document.documentElement.classList.remove('dark')
}
</script>
<%= if root?(assigns) do %>
<link rel="preload" href="/img/shape-1.svg" as="image" />
<link rel="preload" href="/img/shape-2.svg" as="image" />
<link rel="preload" href="/img/shape-3.svg" as="image" />
<% end %>
<%= tags(assigns) || assigns.tags %>
<%= Vite.vite_client() %>
<%= Vite.vite_snippet("src/main.ts") %>
</head>
<body>
<noscript>
<strong>

View file

@ -6,6 +6,7 @@ defmodule Mobilizon.Web.PageView do
use Mobilizon.Web, :view
alias Mobilizon.Actors.Actor
alias Mobilizon.Config
alias Mobilizon.Discussions.{Comment, Discussion}
alias Mobilizon.Events.Event
alias Mobilizon.Posts.Post
@ -91,4 +92,27 @@ defmodule Mobilizon.Web.PageView do
def root?(assigns) do
assigns |> Map.get(:conn, %{request_path: "/"}) |> Map.get(:request_path, "/") == "/"
end
defp favicon do
case Config.instance_favicon() do
%{file: %{url: url}, metadata: metadata} ->
%{
src: url,
sizes:
case metadata do
%{width: width} -> "#{width}x#{width}"
_ -> "any"
end
}
_ ->
%{
src: "/img/icons/apple-touch-icon-152x152.png",
sizes: "152x152"
}
end
end
def favicon_url, do: Map.get(favicon(), :src)
def favicon_sizes, do: Map.get(favicon(), :sizes)
end

25
mix.exs
View file

@ -1,7 +1,7 @@
defmodule Mobilizon.Mixfile do
use Mix.Project
@version "4.0.2"
@version "5.0.0-beta.1"
def project do
[
@ -121,10 +121,12 @@ defmodule Mobilizon.Mixfile do
|> to_string()
|> String.split()
|> Enum.map(fn strategy_entry ->
with [_strategy, dependency] <- String.split(strategy_entry, ":") do
dependency
else
[strategy] -> "ueberauth_#{strategy}"
case String.split(strategy_entry, ":") do
[_strategy, dependency] ->
dependency
[strategy] ->
"ueberauth_#{strategy}"
end
end)
@ -144,7 +146,6 @@ defmodule Mobilizon.Mixfile do
{:phoenix_live_view, "~> 0.20.0"},
{:phoenix_view, "~> 2.0"},
{:gettext, "~> 0.24"},
{:cowboy, "~> 2.6"},
{:guardian, "~> 2.0"},
{:guardian_db, "~> 3.0.0"},
{:guardian_phoenix, "~> 2.0"},
@ -169,7 +170,6 @@ defmodule Mobilizon.Mixfile do
{:absinthe_phoenix, "~> 2.0.1"},
{:absinthe_plug, "~> 1.5.0"},
{:dataloader, "~> 2.0"},
{:plug_cowboy, "~> 2.0"},
{:atomex, "~> 0.4"},
{:cachex, "~> 3.1"},
{:geohax, "~> 1.0.0"},
@ -185,7 +185,7 @@ defmodule Mobilizon.Mixfile do
{:floki, "~> 0.31"},
{:ip_reserved, "~> 0.1.0"},
{:fast_sanitize, "~> 0.1"},
{:ueberauth, "0.10.5", override: true},
{:ueberauth, "0.10.8", override: true},
{:ueberauth_twitter, "~> 0.4"},
{:ueberauth_discord, "~> 0.7"},
{:ueberauth_github, "~> 0.8.1"},
@ -221,6 +221,7 @@ defmodule Mobilizon.Mixfile do
{:rajska, github: "tcitworld/rajska", branch: "mobilizon"},
{:hammer, "~> 6.1"},
{:tls_certificate_check, "~> 1.20"},
{:bandit, "~> 1.0"},
# Dev and test dependencies
{:phoenix_live_reload, "~> 1.2", only: [:dev, :e2e]},
{:ex_machina, "~> 2.3", only: [:dev, :test]},
@ -238,7 +239,9 @@ defmodule Mobilizon.Mixfile do
{:doctor, "~> 0.21", only: :dev},
{:haversine, "~> 0.1.0"},
{:ecto_dev_logger, "~> 0.7"},
{:credo_code_climate, "~> 0.1.0", only: [:dev, :test]}
{:credo_code_climate, "~> 0.1.0", only: [:dev, :test]},
# Generate nix dependencies
{:deps_nix, "~> 0.0", only: :dev}
] ++ oauth_deps()
end
@ -283,7 +286,7 @@ defmodule Mobilizon.Mixfile do
File.rm_rf!("test/uploads")
end
defp docs() do
defp docs do
[
source_ref: "v#{@version}",
groups_for_modules: groups_for_modules(),
@ -323,7 +326,7 @@ defmodule Mobilizon.Mixfile do
]
end
defp groups_for_modules() do
defp groups_for_modules do
[
Models: [
~r/Mobilizon.Actors~r/,

View file

@ -4,6 +4,7 @@
"absinthe_plug": {:hex, :absinthe_plug, "1.5.8", "38d230641ba9dca8f72f1fed2dfc8abd53b3907d1996363da32434ab6ee5d6ab", [:mix], [{:absinthe, "~> 1.5", [hex: :absinthe, repo: "hexpm", optional: false]}, {:plug, "~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bbb04176647b735828861e7b2705465e53e2cf54ccf5a73ddd1ebd855f996e5a"},
"argon2_elixir": {:hex, :argon2_elixir, "4.0.0", "7f6cd2e4a93a37f61d58a367d82f830ad9527082ff3c820b8197a8a736648941", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "f9da27cf060c9ea61b1bd47837a28d7e48a8f6fa13a745e252556c14f9132c7f"},
"atomex": {:hex, :atomex, "0.5.1", "706a8241fd6d1719b27a77b6d1192d2f85e6ecc78e6eadab29207d8cb9bb7ae5", [:mix], [{:xml_builder, "~> 2.1", [hex: :xml_builder, repo: "hexpm", optional: false]}], "hexpm", "6248891b5fcab8503982e090eedeeadb757a6311c2ef2e2998b874f7d319ab3f"},
"bandit": {:hex, :bandit, "1.2.3", "a98d664a96fec23b68e776062296d76a94b4459795b38209f4ae89cb4225709c", [:mix], [{:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "3e29150245a9b5f56944434e5240966e75c917dad248f689ab589b32187a81af"},
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
"cachex": {:hex, :cachex, "3.6.0", "14a1bfbeee060dd9bec25a5b6f4e4691e3670ebda28c8ba2884b12fe30b36bf8", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "ebf24e373883bc8e0c8d894a63bbe102ae13d918f790121f5cfe6e485cc8e2e2"},
"castore": {:hex, :castore, "1.0.5", "9eeebb394cc9a0f3ae56b813459f990abb0a3dedee1be6b27fdb50301930502f", [:mix], [], "hexpm", "8d7c597c3e4a64c395980882d4bca3cebb8d74197c590dc272cfd3b6a6310578"},
@ -12,29 +13,26 @@
"codepagex": {:hex, :codepagex, "0.1.6", "49110d09a25ee336a983281a48ef883da4c6190481e0b063afe2db481af6117e", [:mix], [], "hexpm", "1521461097dde281edf084062f525a4edc6a5e49f4fd1f5ec41c9c4955d5bd59"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
"comeonin": {:hex, :comeonin, "5.4.0", "246a56ca3f41d404380fc6465650ddaa532c7f98be4bda1b4656b3a37cc13abe", [:mix], [], "hexpm", "796393a9e50d01999d56b7b8420ab0481a7538d0caf80919da493b4a6e51faf1"},
"connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
"cors_plug": {:hex, :cors_plug, "3.0.3", "7c3ac52b39624bc616db2e937c282f3f623f25f8d550068b6710e58d04a0e330", [:mix], [{:plug, "~> 1.13", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "3f2d759e8c272ed3835fab2ef11b46bddab8c1ab9528167bd463b6452edf830d"},
"cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
"cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"},
"credo": {:hex, :credo, "1.7.2", "fdee3a7cb553d8f2e773569181f0a4a2bb7d192e27e325404cc31b354f59d68c", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "dd15d6fbc280f6cf9b269f41df4e4992dee6615939653b164ef951f60afcb68e"},
"credo": {:hex, :credo, "1.7.5", "643213503b1c766ec0496d828c90c424471ea54da77c8a168c725686377b9545", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "f799e9b5cd1891577d8c773d245668aa74a2fcd15eb277f51a0131690ebfb3fd"},
"credo_code_climate": {:hex, :credo_code_climate, "0.1.0", "1c4efbd11cb0244622ed5f09246b9afbbf796316ce03e78f67db6d81271d2978", [:mix], [{:credo, "~> 1.5", [hex: :credo, repo: "hexpm", optional: false]}, {:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "75529fe38056f4e229821d604758282838b8397c82e2c12e409fda16b16821ca"},
"dataloader": {:hex, :dataloader, "2.0.0", "49b42d60b9bb06d761a71d7b034c4b34787957e713d4fae15387a25fcd639112", [:mix], [{:ecto, ">= 3.4.3 and < 4.0.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:opentelemetry_process_propagator, "~> 0.2.1", [hex: :opentelemetry_process_propagator, repo: "hexpm", optional: true]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "09d61781b76ce216e395cdbc883ff00d00f46a503e215c22722dba82507dfef0"},
"dataloader": {:hex, :dataloader, "2.0.1", "fa06b057b432b993203003fbff5ff040b7f6483a77e732b7dfc18f34ded2634f", [:mix], [{:ecto, ">= 3.4.3 and < 4.0.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:opentelemetry_process_propagator, "~> 0.3 or ~> 0.2.1", [hex: :opentelemetry_process_propagator, repo: "hexpm", optional: true]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "da7ff00890e1b14f7457419b9508605a8e66ae2cc2d08c5db6a9f344550efa11"},
"db_connection": {:hex, :db_connection, "2.6.0", "77d835c472b5b67fc4f29556dee74bf511bbafecdcaf98c27d27fa5918152086", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c2f992d15725e721ec7fbc1189d4ecdb8afef76648c746a8e1cad35e3b8a35f3"},
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
"deps_nix": {:hex, :deps_nix, "0.5.2", "81af6ec4614de6b1012bf335338ededb61b4153b4b0eae62bc12886fc84b6578", [:mix], [], "hexpm", "8b6bbd21dfefa6e2b432d9f3228d66c88189b1b382eb2c0cdb8f14567118b104"},
"dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"},
"digital_token": {:hex, :digital_token, "0.6.0", "13e6de581f0b1f6c686f7c7d12ab11a84a7b22fa79adeb4b50eec1a2d278d258", [:mix], [{:cldr_utils, "~> 2.17", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "2455d626e7c61a128b02a4a8caddb092548c3eb613ac6f6a85e4cbb6caddc4d1"},
"doctor": {:hex, :doctor, "0.21.0", "20ef89355c67778e206225fe74913e96141c4d001cb04efdeba1a2a9704f1ab5", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "a227831daa79784eb24cdeedfa403c46a4cb7d0eab0e31232ec654314447e4e0"},
"earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"},
"eblurhash": {:hex, :eblurhash, "1.2.2", "7da4255aaea984b31bb71155f673257353b0e0554d0d30dcf859547e74602582", [:rebar3], [], "hexpm", "8c20ca00904de023a835a9dcb7b7762fed32264c85a80c3cafa85288e405044c"},
"ecto": {:hex, :ecto, "3.11.1", "4b4972b717e7ca83d30121b12998f5fcdc62ba0ed4f20fd390f16f3270d85c3e", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ebd3d3772cd0dfcd8d772659e41ed527c28b2a8bde4b00fe03e0463da0f1983b"},
"ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"},
"ecto_autoslug_field": {:hex, :ecto_autoslug_field, "3.1.0", "ddf26e814baf3c32c6aebfed56a637f10a097db83f65d71e6f2d1e7faf2e9e51", [:mix], [{:ecto, ">= 3.7.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:slugify, "~> 1.3", [hex: :slugify, repo: "hexpm", optional: false]}], "hexpm", "b6ddd614805263e24b5c169532c934440d0289181cce873061fca3a8e92fd9ff"},
"ecto_dev_logger": {:hex, :ecto_dev_logger, "0.10.0", "5b3a3900b845e0d40127bed9bdf9d02bf20aa38198a60fe108cddff63ed0048f", [:mix], [{:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "a55e58bad5d5c9b8ef2a3c3347dbdf7efa880a5371cf1457e44b41f489a43927"},
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
"ecto_shortuuid": {:hex, :ecto_shortuuid, "0.2.0", "57cae7b6016cc56a04457b4fc8f63957398dfd9023ff3e900eaf6805a40f8043", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:shortuuid, "~> 2.1 or ~> 3.0", [hex: :shortuuid, repo: "hexpm", optional: false]}], "hexpm", "b92e3b71e86be92f5a7ef6f3de170e7864454e630f7b01dd930414baf38efb65"},
"ecto_sql": {:hex, :ecto_sql, "3.11.1", "e9abf28ae27ef3916b43545f9578b4750956ccea444853606472089e7d169470", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ce14063ab3514424276e7e360108ad6c2308f6d88164a076aac8a387e1fea634"},
"elixir_feed_parser": {:hex, :elixir_feed_parser, "2.1.0", "bb96fb6422158dc7ad59de62ef211cc69d264acbbe63941a64a5dce97bbbc2e6", [:mix], [{:timex, "~> 3.4", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm", "2d3c62fe7b396ee3b73d7160bc8fadbd78bfe9597c98c7d79b3f1038d9cba28f"},
"elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"},
"elixir_make": {:hex, :elixir_make, "0.7.8", "505026f266552ee5aabca0b9f9c229cbb496c689537c9f922f3eb5431157efc7", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "7a71945b913d37ea89b06966e1342c85cfe549b15e6d6d081e8081c493062c07"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"erlport": {:hex, :erlport, "0.11.0", "8bb46a520e6eb9146e655fbf9b824433d9d532194667069d9aa45696aae9684b", [:rebar3], [], "hexpm", "8eb136ccaf3948d329b8d1c3278ad2e17e2a7319801bc4cc2da6db278204eee4"},
"eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"},
@ -43,9 +41,9 @@
"ex_cldr_currencies": {:hex, :ex_cldr_currencies, "2.15.1", "e92ba17c41e7405b7784e0e65f406b5f17cfe313e0e70de9befd653e12854822", [:mix], [{:ex_cldr, "~> 2.34", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "31df8bd37688340f8819bdd770eb17d659652078d34db632b85d4a32864d6a25"},
"ex_cldr_dates_times": {:hex, :ex_cldr_dates_times, "2.16.0", "d9848a5de83b6f1bcba151cc43d63b5c6311813cd605b1df1afd896dfdd21001", [:mix], [{:calendar_interval, "~> 0.2", [hex: :calendar_interval, repo: "hexpm", optional: true]}, {:ex_cldr_calendars, "~> 1.22", [hex: :ex_cldr_calendars, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.31", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:tz, "~> 0.26", [hex: :tz, repo: "hexpm", optional: true]}], "hexpm", "0f2f250d479cadda4e0ef3a5e3d936ae7ba1a3f1199db6791e284e86203495b1"},
"ex_cldr_languages": {:hex, :ex_cldr_languages, "0.3.3", "9787002803552b15a7ade19496c9e46fc921baca992ea80d0394e11fe3acea45", [:mix], [{:ex_cldr, "~> 2.25", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "22fb1fef72b7b4b4872d243b34e7b83734247a78ad87377986bf719089cc447a"},
"ex_cldr_numbers": {:hex, :ex_cldr_numbers, "2.32.3", "b631ff94c982ec518e46bf4736000a30a33d6b58facc085d5f240305f512ad4a", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:digital_token, "~> 0.3 or ~> 1.0", [hex: :digital_token, repo: "hexpm", optional: false]}, {:ex_cldr, "~> 2.37", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_currencies, ">= 2.14.2", [hex: :ex_cldr_currencies, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "7b626ff1e59a0ec9c3c5db5ce9ca91a6995e2ab56426b71f3cbf67181ea225f5"},
"ex_cldr_numbers": {:hex, :ex_cldr_numbers, "2.32.4", "5562148dfc631b04712983975093d2aac29df30b3bf2f7257e0c94b85b72e91b", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:digital_token, "~> 0.3 or ~> 1.0", [hex: :digital_token, repo: "hexpm", optional: false]}, {:ex_cldr, "~> 2.37", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_currencies, ">= 2.14.2", [hex: :ex_cldr_currencies, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "6fd5a82f0785418fa8b698c0be2b1845dff92b77f1b3172c763d37868fb503d2"},
"ex_cldr_plugs": {:hex, :ex_cldr_plugs, "1.3.1", "ae58748df815ad21b8618830374a28b2ab593230e5df70ed9f647e953a884bec", [:mix], [{:ex_cldr, "~> 2.37", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:gettext, "~> 0.19", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "4f7b4a5fe061734cef7b62ff29118ed6ac72698cdd7bcfc97495db73611fe0fe"},
"ex_doc": {:hex, :ex_doc, "0.31.0", "06eb1dfd787445d9cab9a45088405593dd3bb7fe99e097eaa71f37ba80c7a676", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "5350cafa6b7f77bdd107aa2199fe277acf29d739aba5aee7e865fc680c62a110"},
"ex_doc": {:hex, :ex_doc, "0.31.1", "8a2355ac42b1cc7b2379da9e40243f2670143721dd50748bf6c3b1184dae2089", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "3178c3a407c557d8343479e1ff117a96fd31bafe52a039079593fb0524ef61b0"},
"ex_ical": {:hex, :ex_ical, "0.2.0", "4b928b554614704016cc0c9ee226eb854da9327a1cc460457621ceacb1ac29a6", [:mix], [{:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm", "db76473b2ae0259e6633c6c479a5a4d8603f09497f55c88f9ef4d53d2b75befb"},
"ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"},
"ex_optimizer": {:hex, :ex_optimizer, "0.1.1", "62da37e206fc2233ff7a4e54e40eae365c40f96c81992fcd15b782eb25169b80", [:mix], [{:file_info, "~> 0.0.4", [hex: :file_info, repo: "hexpm", optional: false]}], "hexpm", "e6f5c059bcd58b66be2f6f257fdc4f69b74b0fa5c9ddd669486af012e4b52286"},
@ -53,13 +51,13 @@
"excoveralls": {:hex, :excoveralls, "0.18.0", "b92497e69465dc51bc37a6422226ee690ab437e4c06877e836f1c18daeb35da9", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1109bb911f3cb583401760be49c02cbbd16aed66ea9509fc5479335d284da60b"},
"exgravatar": {:hex, :exgravatar, "2.0.3", "2349709832ee535f826f48db98cddd294ae62b01acb44d539a16419bd8ebc3e5", [:mix], [], "hexpm", "aca18ff9bd8991d3be3e5446d3bdefc051be084c1ffc9ab2d43b3e65339300e1"},
"exkismet": {:git, "https://github.com/tcitworld/exkismet.git", "8b5485fde00fafbde20f315bec387a77f7358334", []},
"expo": {:hex, :expo, "0.5.1", "249e826a897cac48f591deba863b26c16682b43711dd15ee86b92f25eafd96d9", [:mix], [], "hexpm", "68a4233b0658a3d12ee00d27d37d856b1ba48607e7ce20fd376958d0ba6ce92b"},
"expo": {:hex, :expo, "0.5.2", "beba786aab8e3c5431813d7a44b828e7b922bfa431d6bfbada0904535342efe2", [:mix], [], "hexpm", "8c9bfa06ca017c9cb4020fabe980bc7fdb1aaec059fd004c2ab3bff03b1c599c"},
"export": {:hex, :export, "0.1.1", "6dfd268b0692428f89b9285859a2dc02b6dcd2e8fdfbca34ac6e6a331351df91", [:mix], [{:erlport, "~> 0.9", [hex: :erlport, repo: "hexpm", optional: false]}], "hexpm", "3da7444ff4053f1824352f4bdb13fbd2c28c93c2011786fb686b649fdca1021f"},
"fast_html": {:hex, :fast_html, "2.2.0", "6c5ef1be087a4ed613b0379c13f815c4d11742b36b67bb52cee7859847c84520", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "064c4f23b4a6168f9187dac8984b056f2c531bb0787f559fd6a8b34b38aefbae"},
"fast_html": {:hex, :fast_html, "2.3.0", "08c1d8ead840dd3060ba02c761bed9f37f456a1ddfe30bcdcfee8f651cec06a6", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "f18e3c7668f82d3ae0b15f48d48feeb257e28aa5ab1b0dbf781c7312e5da029d"},
"fast_sanitize": {:hex, :fast_sanitize, "0.2.3", "67b93dfb34e302bef49fec3aaab74951e0f0602fd9fa99085987af05bd91c7a5", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "e8ad286d10d0386e15d67d0ee125245ebcfbc7d7290b08712ba9013c8c5e56e2"},
"file_info": {:hex, :file_info, "0.0.4", "2e0e77f211e833f38ead22cb29ce53761d457d80b3ffe0ffe0eb93880b0963b2", [:mix], [{:mimetype_parser, "~> 0.1.2", [hex: :mimetype_parser, repo: "hexpm", optional: false]}], "hexpm", "50e7ad01c2c8b9339010675fe4dc4a113b8d6ca7eddce24d1d74fd0e762781a5"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"floki": {:hex, :floki, "0.35.2", "87f8c75ed8654b9635b311774308b2760b47e9a579dabf2e4d5f1e1d42c39e0b", [:mix], [], "hexpm", "6b05289a8e9eac475f644f09c2e4ba7e19201fd002b89c28c1293e7bd16773d9"},
"floki": {:hex, :floki, "0.35.4", "cc947b446024732c07274ac656600c5c4dc014caa1f8fb2dfff93d275b83890d", [:mix], [], "hexpm", "27fa185d3469bd8fc5947ef0f8d5c4e47f0af02eb6b070b63c868f69e3af0204"},
"gen_smtp": {:hex, :gen_smtp, "1.2.0", "9cfc75c72a8821588b9b9fe947ae5ab2aed95a052b81237e0928633a13276fd3", [:rebar3], [{:ranch, ">= 1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "5ee0375680bca8f20c4d85f58c2894441443a743355430ff33a783fe03296779"},
"geo": {:hex, :geo, "3.6.0", "00c9c6338579f67e91cd5950af4ae2eb25cdce0c3398718c232539f61625d0bd", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "1dbdebf617183b54bc3c8ad7a36531a9a76ada8ca93f75f573b0ae94006168da"},
"geo_postgis": {:hex, :geo_postgis, "3.5.0", "e3675b6276b8c2166dc20a6fa9d992eb73c665de2b09b666d09c7824dc8a8300", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:geo, "~> 3.5", [hex: :geo, repo: "hexpm", optional: false]}, {:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm", "0bebc5b00f8b11835066bd6213fbeeec03704b4a1c206920b81c1ec2201d185f"},
@ -71,29 +69,30 @@
"guardian_db": {:hex, :guardian_db, "3.0.0", "c42902e3f1af1ba1e2d0c10913b926a1421f3a7e38eb4fc382b715c17489abdb", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:guardian, "~> 1.0 or ~> 2.0", [hex: :guardian, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "9c2ec4278efa34f9f1cc6ba795e552d41fdc7ffba5319d67eeb533b89392d183"},
"guardian_phoenix": {:hex, :guardian_phoenix, "2.0.1", "89a817265af09a6ddf7cb1e77f17ffca90cea2db10ff888375ef34502b2731b1", [:mix], [{:guardian, "~> 2.0", [hex: :guardian, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.3", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "21f439246715192b231f228680465d1ed5fbdf01555a4a3b17165532f5f9a08c"},
"hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"},
"hammer": {:hex, :hammer, "6.1.0", "f263e3c3e9946bd410ea0336b2abe0cb6260af4afb3a221e1027540706e76c55", [:make, :mix], [{:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}], "hexpm", "b47e415a562a6d072392deabcd58090d8a41182cf9044cdd6b0d0faaaf68ba57"},
"hammer": {:hex, :hammer, "6.2.1", "5ae9c33e3dceaeb42de0db46bf505bd9c35f259c8defb03390cd7556fea67ee2", [:mix], [{:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}], "hexpm", "b9476d0c13883d2dc0cc72e786bac6ac28911fba7cc2e04b70ce6a6d9c4b2bdc"},
"haversine": {:hex, :haversine, "0.1.0", "14240e90dae07c9459f538d12a811492f655d95fc68f999403503b4f6c4ec522", [:mix], [], "hexpm", "54dc48e895bc18a59437a37026c873634e17b648a64cb87bfafb96f64d607060"},
"hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
"html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"},
"http_signatures": {:hex, :http_signatures, "0.1.2", "ed1cc7043abcf5bb4f30d68fb7bad9d618ec1a45c4ff6c023664e78b67d9c406", [:mix], [], "hexpm", "f08aa9ac121829dae109d608d83c84b940ef2f183ae50f2dd1e9a8bc619d8be7"},
"httpoison": {:hex, :httpoison, "1.8.2", "9eb9c63ae289296a544842ef816a85d881d4a31f518a0fec089aaa744beae290", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "2bb350d26972e30c96e2ca74a1aaf8293d61d0742ff17f01e0279fef11599921"},
"icalendar": {:git, "https://github.com/tcitworld/icalendar.git", "1033d922c82a7223db0ec138e2316557b70ff49f", []},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"inet_cidr": {:hex, :inet_cidr, "1.0.4", "a05744ab7c221ca8e395c926c3919a821eb512e8f36547c062f62c4ca0cf3d6e", [:mix], [], "hexpm", "64a2d30189704ae41ca7dbdd587f5291db5d1dda1414e0774c29ffc81088c1bc"},
"inet_cidr": {:hex, :inet_cidr, "1.0.8", "d26bb7bdbdf21ae401ead2092bf2bb4bf57fe44a62f5eaa5025280720ace8a40", [:mix], [], "hexpm", "d5b26da66603bb56c933c65214c72152f0de9a6ea53618b56d63302a68f6a90e"},
"ip_reserved": {:hex, :ip_reserved, "0.1.1", "e5112d71f1abf05207f82fd9597d369a5fde1e0b6d1bbe77c02a99bb26ecdc33", [:mix], [{:inet_cidr, "~> 1.0.0", [hex: :inet_cidr, repo: "hexpm", optional: false]}], "hexpm", "55fcd2b6e211caef09ea3f54ef37d43030bec486325d12fe865ab5ed8140a4fe"},
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
"jose": {:hex, :jose, "1.11.6", "613fda82552128aa6fb804682e3a616f4bc15565a048dabd05b1ebd5827ed965", [:mix, :rebar3], [], "hexpm", "6275cb75504f9c1e60eeacb771adfeee4905a9e182103aa59b53fed651ff9738"},
"jumper": {:hex, :jumper, "1.0.2", "68cdcd84472a00ac596b4e6459a41b3062d4427cbd4f1e8c8793c5b54f1406a7", [:mix], [], "hexpm", "9b7782409021e01ab3c08270e26f36eb62976a38c1aa64b2eaf6348422f165e1"},
"junit_formatter": {:hex, :junit_formatter, "3.3.1", "c729befb848f1b9571f317d2fefa648e9d4869befc4b2980daca7c1edc468e40", [:mix], [], "hexpm", "761fc5be4b4c15d8ba91a6dafde0b2c2ae6db9da7b8832a55b5a1deb524da72b"},
"linkify": {:hex, :linkify, "0.5.3", "5f8143d8f61f5ff08d3aeeff47ef6509492b4948d8f08007fbf66e4d2246a7f2", [:mix], [], "hexpm", "3ef35a1377d47c25506e07c1c005ea9d38d700699d92ee92825f024434258177"},
"makeup": {:hex, :makeup, "1.1.1", "fa0bc768698053b2b3869fa8a62616501ff9d11a562f3ce39580d60860c3a55e", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5dc62fbdd0de44de194898b6710692490be74baa02d9d108bc29f007783b0b48"},
"makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"},
"makeup_erlang": {:hex, :makeup_erlang, "0.1.3", "d684f4bac8690e70b06eb52dad65d26de2eefa44cd19d64a8095e1417df7c8fd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "b78dc853d2e670ff6390b605d807263bf606da3c82be37f9d7f68635bd886fc9"},
"makeup_erlang": {:hex, :makeup_erlang, "0.1.5", "e0ff5a7c708dda34311f7522a8758e23bfcd7d8d8068dc312b5eb41c6fd76eba", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "94d2e986428585a21516d7d7149781480013c56e30c6a233534bedf38867a59a"},
"meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"mimetype_parser": {:hex, :mimetype_parser, "0.1.3", "628ac9fe56aa7edcedb534d68397dd66674ab82493c8ebe39acb9a19b666099d", [:mix], [], "hexpm", "7d8f80c567807ce78cd93c938e7f4b0a20b1aaaaab914bf286f68457d9f7a852"},
"mix_test_watch": {:hex, :mix_test_watch, "1.1.1", "eee6fc570d77ad6851c7bc08de420a47fd1e449ef5ccfa6a77ef68b72e7e51ad", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "f82262b54dee533467021723892e15c3267349849f1f737526523ecba4e6baae"},
"mix_test_watch": {:hex, :mix_test_watch, "1.1.2", "431bdccf20b110f1595fe2a0e3c6cffd96d8f706721def5d04d557bc0898c476", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "8ce79fc69a304eec81ab6c1a05de2eb026a8959f65fb47f933ce8eb56018ba35"},
"mmdb2_decoder": {:hex, :mmdb2_decoder, "3.0.1", "78e3aedde88035c6873ada5ceaf41b7f15a6259ed034e0eaca72ccfa937798f0", [:mix], [], "hexpm", "316af0f388fac824782d944f54efe78e7c9691bbbdb0afd5cccdd0510adf559d"},
"mock": {:hex, :mock, "0.3.8", "7046a306b71db2488ef54395eeb74df0a7f335a7caca4a3d3875d1fc81c884dd", [:mix], [{:meck, "~> 0.9.2", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "7fa82364c97617d79bb7d15571193fc0c4fe5afd0c932cef09426b3ee6fe2022"},
"mogrify": {:hex, :mogrify, "0.9.3", "238c782f00271dace01369ad35ae2e9dd020feee3443b9299ea5ea6bed559841", [:mix], [], "hexpm", "0189b1e1de27455f2b9ae8cf88239cefd23d38de9276eb5add7159aea51731e6"},
@ -103,31 +102,30 @@
"nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"},
"oauth2": {:hex, :oauth2, "2.1.0", "beb657f393814a3a7a8a15bd5e5776ecae341fd344df425342a3b6f1904c2989", [:mix], [{:tesla, "~> 1.5", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "8ac07f85b3307dd1acfeb0ec852f64161b22f57d0ce0c15e616a1dfc8ebe2b41"},
"oauther": {:hex, :oauther, "1.3.0", "82b399607f0ca9d01c640438b34d74ebd9e4acd716508f868e864537ecdb1f76", [:mix], [], "hexpm", "78eb888ea875c72ca27b0864a6f550bc6ee84f2eeca37b093d3d833fbcaec04e"},
"oban": {:hex, :oban, "2.17.1", "42d6221a1c17b63d81c19e3bad9ea82b59e39c47c1f9b7670ee33628569a449b", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c02686ada7979b00e259c0efbafeae2749f8209747b3460001fe695c5bdbeee6"},
"oban": {:hex, :oban, "2.17.5", "3d1bf04ac701ad3c0241eb1f2eb94ea6b8f2f2a3f99ea828847377d2dd256cfe", [:mix], [{:ecto_sql, "~> 3.10", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "fd3ccbbfdbb2bc77107c8790946f9821a831ed0720688485ee6adcd7863886cf"},
"paasaa": {:hex, :paasaa, "0.6.0", "07c8ed81010caa25db351d474f0c053072c809821c60f9646f7b1547bec52f6d", [:mix], [], "hexpm", "732ddfc21bac0831edb26aec468af3ec2b8997d74f6209810b1cc53199c29f2e"},
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
"phoenix": {:hex, :phoenix, "1.7.10", "02189140a61b2ce85bb633a9b6fd02dff705a5f1596869547aeb2b2b95edd729", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "cf784932e010fd736d656d7fead6a584a4498efefe5b8227e9f383bf15bb79d0"},
"phoenix": {:hex, :phoenix, "1.7.11", "1d88fc6b05ab0c735b250932c4e6e33bfa1c186f76dcf623d8dd52f07d6379c7", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "b1ec57f2e40316b306708fe59b92a16b9f6f4bf50ccfa41aa8c7feb79e0ec02a"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.4.3", "86e9878f833829c3f66da03d75254c155d91d72a201eb56ae83482328dc7ca93", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "d36c401206f3011fefd63d04e8ef626ec8791975d9d107f9a0817d426f61ac07"},
"phoenix_html": {:hex, :phoenix_html, "3.3.3", "380b8fb45912b5638d2f1d925a3771b4516b9a78587249cabe394e0a5d579dc9", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "923ebe6fec6e2e3b3e569dfbdc6560de932cd54b000ada0208b5f45024bdd76c"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.4.1", "2aff698f5e47369decde4357ba91fc9c37c6487a512b41732818f2204a8ef1d3", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "9bffb834e7ddf08467fe54ae58b5785507aaba6255568ae22b4d46e2bb3615ab"},
"phoenix_live_view": {:hex, :phoenix_live_view, "0.20.3", "8b6406bc0a451f295407d7acff7f234a6314be5bbe0b3f90ed82b07f50049878", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a8e4385e05618b424779f894ed2df97d3c7518b7285fcd11979077ae6226466b"},
"phoenix_live_view": {:hex, :phoenix_live_view, "0.20.10", "a790858cf9b63815bb93d1748e26c73f0c7f09f20873562f4f307dd52b0ca32f", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "daa17b3fbdfd6347aaade4db01a5dd24d23af0f4344e2e24934e8adfb4a11607"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"},
"phoenix_swoosh": {:hex, :phoenix_swoosh, "1.2.0", "a544d83fde4a767efb78f45404a74c9e37b2a9c5ea3339692e65a6966731f935", [:mix], [{:finch, "~> 0.8", [hex: :finch, repo: "hexpm", optional: true]}, {:hackney, "~> 1.10", [hex: :hackney, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.5", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "e88d117251e89a16b92222415a6d87b99a96747ddf674fc5c7631de734811dba"},
"phoenix_swoosh": {:hex, :phoenix_swoosh, "1.2.1", "b74ccaa8046fbc388a62134360ee7d9742d5a8ae74063f34eb050279de7a99e1", [:mix], [{:finch, "~> 0.8", [hex: :finch, repo: "hexpm", optional: true]}, {:hackney, "~> 1.10", [hex: :hackney, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.5", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "4000eeba3f9d7d1a6bf56d2bd56733d5cadf41a7f0d8ffe5bb67e7d667e204a2"},
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
"phoenix_view": {:hex, :phoenix_view, "2.0.3", "4d32c4817fce933693741deeb99ef1392619f942633dde834a5163124813aad3", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "cd34049af41be2c627df99cd4eaa71fc52a328c0c3d8e7d4aa28f880c30e7f64"},
"plug": {:hex, :plug, "1.15.2", "94cf1fa375526f30ff8770837cb804798e0045fd97185f0bb9e5fcd858c792a3", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "02731fa0c2dcb03d8d21a1d941bdbbe99c2946c0db098eee31008e04c6283615"},
"plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"},
"plug": {:hex, :plug, "1.15.3", "712976f504418f6dff0a3e554c40d705a9bcf89a7ccef92fc6a5ef8f16a30a97", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cc4365a3c010a56af402e0809208873d113e9c38c401cabd88027ef4f5c01fd2"},
"plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"},
"poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
"postgrex": {:hex, :postgrex, "0.17.4", "5777781f80f53b7c431a001c8dad83ee167bcebcf3a793e3906efff680ab62b3", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "6458f7d5b70652bc81c3ea759f91736c16a31be000f306d3c64bcdfe9a18b3cc"},
"progress_bar": {:hex, :progress_bar, "3.0.0", "f54ff038c2ac540cfbb4c2bfe97c75e7116ead044f3c2b10c9f212452194b5cd", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "6981c2b25ab24aecc91a2dc46623658e1399c21a2ae24db986b90d678530f2b7"},
"rajska": {:git, "https://github.com/tcitworld/rajska.git", "0c036448e261e8be6a512581c592fadf48982d84", [branch: "mobilizon"]},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"ranch": {:hex, :ranch, "2.1.0", "2261f9ed9574dcfcc444106b9f6da155e6e540b2f82ba3d42b339b93673b72a3", [:make, :rebar3], [], "hexpm", "244ee3fa2a6175270d8e1fc59024fd9dbc76294a321057de8f803b1479e76916"},
"remote_ip": {:hex, :remote_ip, "1.1.0", "cb308841595d15df3f9073b7c39243a1dd6ca56e5020295cb012c76fbec50f2d", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "616ffdf66aaad6a72fc546dabf42eed87e2a99e97b09cbd92b10cc180d02ed74"},
"replug": {:hex, :replug, "0.1.0", "61d35f8c873c0078a23c49579a48f36e45789414b1ec0daee3fd5f4e34221f23", [:mix], [{:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "f71f7a57e944e854fe4946060c6964098e53958074c69fb844b96e0bd58cfa60"},
"sentry": {:hex, :sentry, "8.1.0", "8d235b62fce5f8e067ea1644e30939405b71a5e1599d9529ff82899d11d03f2b", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.6", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, "~> 2.3", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm", "f9fc7641ef61e885510f5e5963c2948b9de1de597c63f781e9d3d6c9c8681ab4"},
"shortuuid": {:hex, :shortuuid, "3.0.0", "028684d9eeed0ad4b800e8481afd854e1a61c526f35952455b2ee4248601e7b8", [:mix], [], "hexpm", "dfd8f80f514cbb91622cb83f4ac0d6e2f06d98cc6d4aeba94444a212289d0d39"},
"sitemapper": {:hex, :sitemapper, "0.7.0", "4aee7930327a9a01b1c9b81d1d42f60c1a295e9f420108eb2d130c317415abd7", [:mix], [{:ex_aws_s3, "~> 2.0", [hex: :ex_aws_s3, repo: "hexpm", optional: true]}, {:xml_builder, "~> 2.1", [hex: :xml_builder, repo: "hexpm", optional: false]}], "hexpm", "60f7a684e5e9fe7f10ac5b69f48b0be2bcbba995afafcb3c143fc0c8ef1f223f"},
"sitemapper": {:hex, :sitemapper, "0.8.0", "50c8c85ed38c013829ce700e8a8d195a2faf4aed8685659b14529dcb6f91fee0", [:mix], [{:ex_aws_s3, "~> 2.0", [hex: :ex_aws_s3, repo: "hexpm", optional: true]}, {:xml_builder, "~> 2.1", [hex: :xml_builder, repo: "hexpm", optional: false]}], "hexpm", "7cd42b454035da457151c9b6a314b688b5bbe5383add95badc65d013c25989c5"},
"sleeplocks": {:hex, :sleeplocks, "1.1.2", "d45aa1c5513da48c888715e3381211c859af34bee9b8290490e10c90bb6ff0ca", [:rebar3], [], "hexpm", "9fe5d048c5b781d6305c1a3a0f40bb3dfc06f49bf40571f3d2d0c57eaa7f59a5"},
"slugger": {:hex, :slugger, "0.3.0", "efc667ab99eee19a48913ccf3d038b1fb9f165fa4fbf093be898b8099e61b6ed", [:mix], [], "hexpm", "20d0ded0e712605d1eae6c5b4889581c3460d92623a930ddda91e0e609b5afba"},
"slugify": {:hex, :slugify, "1.3.1", "0d3b8b7e5c1eeaa960e44dce94382bee34a39b3ea239293e457a9c5b47cc6fd3", [:mix], [], "hexpm", "cb090bbeb056b312da3125e681d98933a360a70d327820e4b7f91645c4d8be76"},
@ -135,14 +133,15 @@
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
"struct_access": {:hex, :struct_access, "1.1.2", "a42e6ceedd9b9ea090ee94a6da089d56e16f374dbbc010c3eebdf8be17df286f", [:mix], [], "hexpm", "e4c411dcc0226081b95709909551fc92b8feb1a3476108348ea7e3f6c12e586a"},
"sweet_xml": {:hex, :sweet_xml, "0.7.4", "a8b7e1ce7ecd775c7e8a65d501bc2cd933bff3a9c41ab763f5105688ef485d08", [:mix], [], "hexpm", "e7c4b0bdbf460c928234951def54fe87edf1a170f6896675443279e2dbeba167"},
"swoosh": {:hex, :swoosh, "1.14.3", "949e6bf6dd469449238a94ec6f19ec10b63fc8753de7f3ebe3d3aeaf772f4c6b", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.4 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6c565103fc8f086bdd96e5c948660af8e20922b7a90a75db261f06a34f805c8b"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
"swoosh": {:hex, :swoosh, "1.15.3", "5c3f05b6e4e08cd4f75ad7e90db3c2b73c9d9de00503cce36a694951c2d69185", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.4 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "97a667b96ca8cc48a4679f6cd1f40a36d8701cf052587298473614caa70f164a"},
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
"tesla": {:hex, :tesla, "1.8.0", "d511a4f5c5e42538d97eef7c40ec4f3e44effdc5068206f42ed859e09e51d1fd", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, ">= 1.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "10501f360cd926a309501287470372af1a6e1cbed0f43949203a4c13300bc79f"},
"thousand_island": {:hex, :thousand_island, "1.3.5", "6022b6338f1635b3d32406ff98d68b843ba73b3aa95cfc27154223244f3a6ca5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2be6954916fdfe4756af3239fb6b6d75d0b8063b5df03ba76fd8a4c87849e180"},
"timex": {:hex, :timex, "3.7.11", "bb95cb4eb1d06e27346325de506bcc6c30f9c6dea40d1ebe390b262fad1862d1", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8b9024f7efbabaf9bd7aa04f65cf8dcd7c9818ca5737677c7b76acbc6a94d1aa"},
"tls_certificate_check": {:hex, :tls_certificate_check, "1.21.0", "042ab2c0c860652bc5cf69c94e3a31f96676d14682e22ec7813bd173ceff1788", [:rebar3], [{:ssl_verify_fun, "~> 1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "6cee6cffc35a390840d48d463541d50746a7b0e421acaadb833cfc7961e490e7"},
"tz_world": {:hex, :tz_world, "1.3.2", "15d331ad1ff22735dfcc8c98bfc7b2a9fdc17f1f071e31e21cdafe2d9318a300", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:geo, "~> 1.0 or ~> 2.0 or ~> 3.3", [hex: :geo, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "d1a345e07b3378c4c902ad54fbd5d54c8c3dd55dba883b7407fe57bcec45ff2a"},
"tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"},
"ueberauth": {:hex, :ueberauth, "0.10.5", "806adb703df87e55b5615cf365e809f84c20c68aa8c08ff8a416a5a6644c4b02", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "3efd1f31d490a125c7ed453b926f7c31d78b97b8a854c755f5c40064bf3ac9e1"},
"ueberauth": {:hex, :ueberauth, "0.10.8", "ba78fbcbb27d811a6cd06ad851793aaf7d27c3b30c9e95349c2c362b344cd8f0", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "f2d3172e52821375bccb8460e5fa5cb91cfd60b19b636b6e57e9759b6f8c10c1"},
"ueberauth_cas": {:hex, :ueberauth_cas, "2.3.1", "df45a1f2c5df8bc80191cbca4baeeed808d697702ec5ebe5bd5d5a264481752f", [:mix], [{:httpoison, "~> 1.8", [hex: :httpoison, repo: "hexpm", optional: false]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.6", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "5068ae2b9e217c2f05aa9a67483a6531e21ba0be9a6f6c8749bb7fd1599be321"},
"ueberauth_discord": {:hex, :ueberauth_discord, "0.7.0", "463f6dfe1ed10a76739331ce8e1dd3600ab611f10524dd828eb3aa50e76e9d43", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.7", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "d6f98ef91abb4ddceada4b7acba470e0e68c4d2de9735ff2f24172a8e19896b4"},
"ueberauth_facebook": {:hex, :ueberauth_facebook, "0.10.0", "0d607fbd1b7c6e0449981571027d869c2d156b8ad20c42e3672346678c05ccf1", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.7", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "bf8ce5d66b1c50da8abff77e8086c1b710bdde63f4acaef19a651ba43a9537a8"},

2040
mix.nix

File diff suppressed because it is too large Load diff

3253
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"name": "mobilizon",
"version": "4.0.2",
"version": "5.0.0-beta.1",
"private": true,
"scripts": {
"dev": "vite",
@ -27,17 +27,17 @@
"mix credo"
]
},
"type": "module",
"dependencies": {
"@apollo/client": "^3.3.16",
"@apollo/client": "^3.9.5",
"@framasoft/socket": "^1.0.0",
"@framasoft/socket-apollo-link": "^1.0.0",
"@oruga-ui/oruga-next": "0.8.12",
"@oruga-ui/theme-oruga": "^0.2.0",
"@fullcalendar/core": "^6.1.10",
"@fullcalendar/daygrid": "^6.1.10",
"@fullcalendar/icalendar": "^6.1.10",
"@fullcalendar/interaction": "^6.1.10",
"@fullcalendar/vue3": "^6.1.10",
"@oruga-ui/oruga-next": "^0.8.2",
"@oruga-ui/theme-oruga": "^0.2.0",
"@sentry/tracing": "^7.1",
"@sentry/vue": "^7.1",
"@tiptap/core": "^2.0.0-beta.41",
@ -77,7 +77,7 @@
"blurhash": "^2.0.0",
"date-fns": "^2.16.0",
"date-fns-tz": "^2.0.0",
"floating-vue": "^2.0.0-beta.24",
"floating-vue": "^5.0.0",
"graphql": "^16.8.1",
"graphql-tag": "^2.10.3",
"hammerjs": "^2.0.8",
@ -90,6 +90,7 @@
"lodash": "^4.17.11",
"ngeohash": "^0.6.3",
"p-debounce": "^4.0.0",
"patch-package": "^8.0.0",
"phoenix": "^1.6",
"postcss": "^8",
"register-service-worker": "^1.7.2",
@ -97,7 +98,7 @@
"tailwindcss": "^3",
"tippy.js": "^6.2.3",
"unfetch": "^5.0.0",
"vue": "^3.2.37",
"vue": "^3.4.20",
"vue-i18n": "9",
"vue-material-design-icons": "^5.1.2",
"vue-matomo": "^4.1.0",
@ -121,9 +122,9 @@
"@types/ngeohash": "^0.6.2",
"@types/phoenix": "^1.5.2",
"@types/sanitize-html": "^2.5.0",
"@vitejs/plugin-vue": "^4.0.0",
"@vitest/coverage-v8": "^0.34.1",
"@vitest/ui": "^0.34.1",
"@vitejs/plugin-vue": "^5.0.0",
"@vitest/coverage-v8": "^1.2.2",
"@vitest/ui": "^1.2.2",
"@vue/eslint-config-prettier": "^9.0.0",
"@vue/eslint-config-typescript": "^12.0.0",
"@vue/test-utils": "^2.0.2",
@ -134,8 +135,8 @@
"eslint-plugin-vue": "^9.3.0",
"flush-promises": "^1.0.2",
"histoire": "^0.17.0",
"husky": "^8.0.3",
"jsdom": "^22.0.0",
"husky": "^9.0.10",
"jsdom": "^24.0.0",
"lint-staged": "^15.1.0",
"mock-apollo-client": "^1.1.0",
"prettier": "^3.0.0",
@ -143,10 +144,10 @@
"rollup-plugin-visualizer": "^5.7.1",
"sass": "^1.34.1",
"typescript": "~5.3.2",
"vite": "^4.5.0",
"vite-plugin-pwa": "^0.17.0",
"vite": "^5.0.12",
"vite-svg-loader": "^4.0.0",
"vitest": "^0.34.1",
"vite-plugin-pwa": "^0.19.0",
"vitest": "^1.2.2",
"vue-i18n-extract": "^2.0.4",
"vue-router-mock": "^1.0.0"
}

View file

@ -0,0 +1,66 @@
diff --git a/node_modules/vue-i18n-extract/dist/vue-i18n-extract.modern.mjs b/node_modules/vue-i18n-extract/dist/vue-i18n-extract.modern.mjs
index 670733e..872d1af 100644
--- a/node_modules/vue-i18n-extract/dist/vue-i18n-extract.modern.mjs
+++ b/node_modules/vue-i18n-extract/dist/vue-i18n-extract.modern.mjs
@@ -38,7 +38,7 @@ var defaultConfig = {
};
function initCommand() {
- fs.writeFileSync(path.resolve(process.cwd(), './vue-i18n-extract.config.js'), `module.exports = ${JSON.stringify(defaultConfig, null, 2)}`);
+ fs.writeFileSync(path.resolve(process.cwd(), './vue-i18n-extract.config.cjs'), `module.exports = ${JSON.stringify(defaultConfig, null, 2)}`);
}
function resolveConfig() {
const argvOptions = cac().parse(process.argv, {
@@ -47,7 +47,7 @@ function resolveConfig() {
let options;
try {
- const pathToConfigFile = path.resolve(process.cwd(), './vue-i18n-extract.config.js'); // eslint-disable-next-line @typescript-eslint/no-var-requires
+ const pathToConfigFile = path.resolve(process.cwd(), './vue-i18n-extract.config.cjs'); // eslint-disable-next-line @typescript-eslint/no-var-requires
const configOptions = require(pathToConfigFile);
diff --git a/node_modules/vue-i18n-extract/dist/vue-i18n-extract.umd.js b/node_modules/vue-i18n-extract/dist/vue-i18n-extract.umd.js
index ca19c7a..11cb846 100644
--- a/node_modules/vue-i18n-extract/dist/vue-i18n-extract.umd.js
+++ b/node_modules/vue-i18n-extract/dist/vue-i18n-extract.umd.js
@@ -45,7 +45,7 @@
};
function initCommand() {
- fs__default["default"].writeFileSync(path__default["default"].resolve(process.cwd(), './vue-i18n-extract.config.js'), `module.exports = ${JSON.stringify(defaultConfig, null, 2)}`);
+ fs__default["default"].writeFileSync(path__default["default"].resolve(process.cwd(), './vue-i18n-extract.config.cjs'), `module.exports = ${JSON.stringify(defaultConfig, null, 2)}`);
}
function resolveConfig() {
const argvOptions = cac__default["default"]().parse(process.argv, {
@@ -54,7 +54,7 @@
let options;
try {
- const pathToConfigFile = path__default["default"].resolve(process.cwd(), './vue-i18n-extract.config.js'); // eslint-disable-next-line @typescript-eslint/no-var-requires
+ const pathToConfigFile = path__default["default"].resolve(process.cwd(), './vue-i18n-extract.config.cjs'); // eslint-disable-next-line @typescript-eslint/no-var-requires
const configOptions = require(pathToConfigFile);
diff --git a/node_modules/vue-i18n-extract/src/config-file/index.ts b/node_modules/vue-i18n-extract/src/config-file/index.ts
index 3db836f..744bd74 100644
--- a/node_modules/vue-i18n-extract/src/config-file/index.ts
+++ b/node_modules/vue-i18n-extract/src/config-file/index.ts
@@ -5,7 +5,7 @@ import defaultConfig from './vue-i18n-extract.config';
export function initCommand(): void {
fs.writeFileSync(
- path.resolve(process.cwd(), './vue-i18n-extract.config.js'),
+ path.resolve(process.cwd(), './vue-i18n-extract.config.cjs'),
`module.exports = ${JSON.stringify(defaultConfig, null, 2)}`,
);
}
@@ -16,7 +16,7 @@ export function resolveConfig (): Record<string, string> {
let options;
try {
- const pathToConfigFile = path.resolve(process.cwd(), './vue-i18n-extract.config.js');
+ const pathToConfigFile = path.resolve(process.cwd(), './vue-i18n-extract.config.cjs');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const configOptions = require(pathToConfigFile);

View file

@ -1,4 +1,4 @@
module.exports = {
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},

View file

@ -214,7 +214,7 @@ msgstr ""
#: lib/web/templates/email/email_direct_activity.html.heex:230
#: lib/web/templates/email/email_direct_activity.text.eex:23
#, elixir-format
#, elixir-format, elixir-autogen
msgid "View one more activity"
msgid_plural "View %{count} more activities"
msgstr[0] ""
@ -224,7 +224,7 @@ msgstr[1] ""
#: lib/web/templates/email/email_direct_activity.html.heex:60
#: lib/web/templates/email/email_direct_activity.text.eex:6
#: lib/web/templates/email/email_direct_activity.text.eex:7
#, elixir-format
#, elixir-format, elixir-autogen
msgid "There has been an activity!"
msgid_plural "There has been some activity!"
msgstr[0] ""

View file

@ -216,7 +216,7 @@ msgstr ""
#: lib/web/templates/email/email_direct_activity.html.heex:230
#: lib/web/templates/email/email_direct_activity.text.eex:23
#, elixir-format
#, elixir-format, elixir-autogen
msgid "View one more activity"
msgid_plural "View %{count} more activities"
msgstr[0] ""
@ -230,7 +230,7 @@ msgstr[5] ""
#: lib/web/templates/email/email_direct_activity.html.heex:60
#: lib/web/templates/email/email_direct_activity.text.eex:6
#: lib/web/templates/email/email_direct_activity.text.eex:7
#, elixir-format
#, elixir-format, elixir-autogen
msgid "There has been an activity!"
msgid_plural "There has been some activity!"
msgstr[0] ""

View file

@ -317,7 +317,7 @@ msgid "Mobilizon on %{instance}: email changed"
msgstr ""
#: lib/web/email/notification.ex:52
#, elixir-format
#, elixir-format, elixir-autogen
msgid "One event planned today"
msgid_plural "%{nb_events} events planned today"
msgstr[0] ""
@ -329,7 +329,7 @@ msgstr[5] ""
#: lib/web/templates/email/on_day_notification.html.heex:47
#: lib/web/templates/email/on_day_notification.text.eex:3
#, elixir-format
#, elixir-format, elixir-autogen
msgid "You have one event today:"
msgid_plural "You have %{total} events today:"
msgstr[0] ""
@ -383,7 +383,7 @@ msgid "You have been invited by %{inviter} to join group %{group}"
msgstr ""
#: lib/web/email/notification.ex:81
#, elixir-format
#, elixir-format, elixir-autogen
msgid "One event planned this week"
msgid_plural "%{nb_events} events planned this week"
msgstr[0] ""
@ -394,7 +394,7 @@ msgstr[4] ""
msgstr[5] ""
#: lib/web/email/notification.ex:107
#, elixir-format
#, elixir-format, elixir-autogen
msgid "One participation request for event %{title} to process"
msgid_plural "%{number_participation_requests} participation requests for event %{title} to process"
msgstr[0] ""
@ -406,7 +406,7 @@ msgstr[5] ""
#: lib/web/templates/email/notification_each_week.html.heex:47
#: lib/web/templates/email/notification_each_week.text.eex:3
#, elixir-format
#, elixir-format, elixir-autogen
msgid "You have one event this week:"
msgid_plural "You have %{total} events this week:"
msgstr[0] ""
@ -776,7 +776,7 @@ msgstr ""
#: lib/web/templates/email/notification_each_week.text.eex:11
#: lib/web/templates/email/on_day_notification.html.heex:89
#: lib/web/templates/email/on_day_notification.text.eex:11
#, elixir-format
#, elixir-format, elixir-autogen
msgid "Would you wish to cancel your attendance, visit the event page through the link above and click the « Attending » button."
msgid_plural "Would you wish to cancel your attendance to one or several events, visit the event pages through the links above and click the « Attending » button."
msgstr[0] ""
@ -1076,7 +1076,7 @@ msgstr ""
msgid "Your instance's moderation team has decided to suspend %{group_name} (%{group_address}). You are no longer a member of this group."
msgstr ""
#: lib/web/email/group.ex:108
#: lib/web/email/group.ex:106
#, elixir-autogen, elixir-format
msgid "The group %{group} has been suspended on %{instance}"
msgstr ""
@ -1160,12 +1160,6 @@ msgctxt "terms"
msgid "We reserve the right to modify these Terms at any time. For instance, we may need to change these Terms if we come out with a new feature."
msgstr ""
#: lib/web/templates/api/terms.html.heex:55
#, elixir-autogen, elixir-format
msgctxt "terms"
msgid "When we say “we”, “our”, or “us” in this document, we are referring to the owners, operators and administrators of this Mobilizon instance. The Mobilizon software is provided by the team of Mobilizon contributors, supported by <a href=\"https://framasoft.org\">Framasoft</a>, a French not-for-profit organization advocating for Free/Libre Software. Unless explicitly stated, this Mobilizon instance is an independent service using Mobilizon's source code. You may find more information about this instance on the <a href=\"/about/instance\">\"About this instance\"</a> page."
msgstr ""
#: lib/web/templates/api/terms.html.heex:105
#, elixir-autogen, elixir-format
msgctxt "terms"
@ -1650,7 +1644,7 @@ msgstr ""
#: lib/web/templates/email/pending_participation_notification.html.heex:47
#: lib/web/templates/email/pending_participation_notification.text.eex:4
#, elixir-format
#, elixir-format, elixir-autogen
msgid "You have one pending attendance request to process for the following event:"
msgid_plural "You have %{number_participation_requests} attendance requests to process for the following event:"
msgstr[0] ""
@ -2048,3 +2042,9 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "Well done!"
msgstr ""
#: lib/web/templates/api/terms.html.heex:55
#, elixir-autogen, elixir-format, fuzzy
msgctxt "terms"
msgid "When we say “we”, “our”, or “us” in this document, we are referring to the owners, operators and administrators of this Mobilizon instance. The Mobilizon software is provided by the team of Mobilizon contributors. Unless explicitly stated, this Mobilizon instance is an independent service using Mobilizon's source code. You may find more information about this instance on the <a href=\"/about/instance\">\"About this instance\"</a> page."
msgstr ""

View file

@ -207,13 +207,13 @@ msgstr ""
msgid "The current password is invalid"
msgstr ""
#: lib/graphql/resolvers/admin.ex:334
#: lib/graphql/resolvers/admin.ex:335
#: lib/graphql/resolvers/user.ex:527
#, elixir-autogen, elixir-format
msgid "The new email doesn't seem to be valid"
msgstr ""
#: lib/graphql/resolvers/admin.ex:323
#: lib/graphql/resolvers/admin.ex:324
#: lib/graphql/resolvers/user.ex:514
#, elixir-autogen, elixir-format
msgid "The new email must be different"
@ -647,7 +647,7 @@ msgstr ""
msgid "You don't have permission to delete this token"
msgstr ""
#: lib/graphql/resolvers/admin.ex:56
#: lib/graphql/resolvers/admin.ex:57
#, elixir-autogen, elixir-format
msgid "You need to be logged-in and a moderator to list action logs"
msgstr ""
@ -667,17 +667,17 @@ msgstr ""
msgid "You need to be logged-in and a moderator to view a report"
msgstr ""
#: lib/graphql/resolvers/admin.ex:258
#: lib/graphql/resolvers/admin.ex:259
#, elixir-autogen, elixir-format
msgid "You need to be logged-in and an administrator to access admin settings"
msgstr ""
#: lib/graphql/resolvers/admin.ex:242
#: lib/graphql/resolvers/admin.ex:243
#, elixir-autogen, elixir-format
msgid "You need to be logged-in and an administrator to access dashboard statistics"
msgstr ""
#: lib/graphql/resolvers/admin.ex:283
#: lib/graphql/resolvers/admin.ex:284
#, elixir-autogen, elixir-format
msgid "You need to be logged-in and an administrator to save admin settings"
msgstr ""
@ -964,7 +964,7 @@ msgstr ""
msgid "Failed to update the group"
msgstr ""
#: lib/graphql/resolvers/admin.ex:357
#: lib/graphql/resolvers/admin.ex:358
#: lib/graphql/resolvers/user.ex:547
#, elixir-autogen, elixir-format
msgid "Failed to update user email"
@ -1095,22 +1095,22 @@ msgstr ""
msgid "Your email seems to be using an invalid format"
msgstr ""
#: lib/graphql/resolvers/admin.ex:399
#: lib/graphql/resolvers/admin.ex:400
#, elixir-autogen, elixir-format
msgid "Can't confirm an already confirmed user"
msgstr ""
#: lib/graphql/resolvers/admin.ex:403
#: lib/graphql/resolvers/admin.ex:404
#, elixir-autogen, elixir-format
msgid "Deconfirming users is not supported"
msgstr ""
#: lib/graphql/resolvers/admin.ex:375
#: lib/graphql/resolvers/admin.ex:376
#, elixir-autogen, elixir-format, fuzzy
msgid "The new role must be different"
msgstr ""
#: lib/graphql/resolvers/admin.ex:314
#: lib/graphql/resolvers/admin.ex:315
#, elixir-autogen, elixir-format, fuzzy
msgid "You need to be logged-in and an administrator to edit an user's details"
msgstr ""
@ -1120,7 +1120,7 @@ msgstr ""
msgid "A profile or group with that name already exists"
msgstr ""
#: lib/graphql/resolvers/admin.ex:542
#: lib/graphql/resolvers/admin.ex:560
#, elixir-autogen, elixir-format
msgid "Unable to find an instance to follow at this address"
msgstr ""
@ -1382,7 +1382,7 @@ msgstr ""
msgid "The same push subscription has already been registered"
msgstr ""
#: lib/graphql/resolvers/admin.ex:536
#: lib/graphql/resolvers/admin.ex:554
#, elixir-autogen, elixir-format
msgid "This instance is pending follow approval"
msgstr ""
@ -1392,7 +1392,7 @@ msgstr ""
msgid "Timezone ID %{timezone} is invalid"
msgstr ""
#: lib/graphql/resolvers/admin.ex:539
#: lib/graphql/resolvers/admin.ex:557
#, elixir-autogen, elixir-format, fuzzy
msgid "You are already following this instance"
msgstr ""
@ -1412,12 +1412,12 @@ msgstr ""
msgid "The token you provided is invalid. Make sure that the URL is exactly the one provided inside the email you got."
msgstr ""
#: lib/graphql/resolvers/conversation.ex:161
#: lib/graphql/resolvers/conversation.ex:164
#, elixir-autogen, elixir-format
msgid "Conversation needs to mention at least one participant that's not yourself"
msgstr ""
#: lib/graphql/resolvers/participant.ex:396
#: lib/graphql/resolvers/participant.ex:401
#, elixir-autogen, elixir-format
msgid "There are no participants matching the audience you've selected."
msgstr ""

View file

@ -215,7 +215,7 @@ msgstr ""
#: lib/web/templates/email/email_direct_activity.html.heex:230
#: lib/web/templates/email/email_direct_activity.text.eex:23
#, elixir-format
#, elixir-format, elixir-autogen
msgid "View one more activity"
msgid_plural "View %{count} more activities"
msgstr[0] ""
@ -226,7 +226,7 @@ msgstr[2] ""
#: lib/web/templates/email/email_direct_activity.html.heex:60
#: lib/web/templates/email/email_direct_activity.text.eex:6
#: lib/web/templates/email/email_direct_activity.text.eex:7
#, elixir-format
#, elixir-format, elixir-autogen
msgid "There has been an activity!"
msgid_plural "There has been some activity!"
msgstr[0] ""

View file

@ -315,7 +315,7 @@ msgid "Mobilizon on %{instance}: email changed"
msgstr ""
#: lib/web/email/notification.ex:52
#, elixir-format
#, elixir-format, elixir-autogen
msgid "One event planned today"
msgid_plural "%{nb_events} events planned today"
msgstr[0] ""
@ -324,7 +324,7 @@ msgstr[2] ""
#: lib/web/templates/email/on_day_notification.html.heex:47
#: lib/web/templates/email/on_day_notification.text.eex:3
#, elixir-format
#, elixir-format, elixir-autogen
msgid "You have one event today:"
msgid_plural "You have %{total} events today:"
msgstr[0] ""
@ -375,7 +375,7 @@ msgid "You have been invited by %{inviter} to join group %{group}"
msgstr ""
#: lib/web/email/notification.ex:81
#, elixir-format
#, elixir-format, elixir-autogen
msgid "One event planned this week"
msgid_plural "%{nb_events} events planned this week"
msgstr[0] ""
@ -383,7 +383,7 @@ msgstr[1] ""
msgstr[2] ""
#: lib/web/email/notification.ex:107
#, elixir-format
#, elixir-format, elixir-autogen
msgid "One participation request for event %{title} to process"
msgid_plural "%{number_participation_requests} participation requests for event %{title} to process"
msgstr[0] ""
@ -392,7 +392,7 @@ msgstr[2] ""
#: lib/web/templates/email/notification_each_week.html.heex:47
#: lib/web/templates/email/notification_each_week.text.eex:3
#, elixir-format
#, elixir-format, elixir-autogen
msgid "You have one event this week:"
msgid_plural "You have %{total} events this week:"
msgstr[0] ""
@ -759,7 +759,7 @@ msgstr ""
#: lib/web/templates/email/notification_each_week.text.eex:11
#: lib/web/templates/email/on_day_notification.html.heex:89
#: lib/web/templates/email/on_day_notification.text.eex:11
#, elixir-format
#, elixir-format, elixir-autogen
msgid "Would you wish to cancel your attendance, visit the event page through the link above and click the « Attending » button."
msgid_plural "Would you wish to cancel your attendance to one or several events, visit the event pages through the links above and click the « Attending » button."
msgstr[0] ""
@ -1056,7 +1056,7 @@ msgstr ""
msgid "Your instance's moderation team has decided to suspend %{group_name} (%{group_address}). You are no longer a member of this group."
msgstr ""
#: lib/web/email/group.ex:108
#: lib/web/email/group.ex:106
#, elixir-autogen, elixir-format
msgid "The group %{group} has been suspended on %{instance}"
msgstr ""
@ -1140,12 +1140,6 @@ msgctxt "terms"
msgid "We reserve the right to modify these Terms at any time. For instance, we may need to change these Terms if we come out with a new feature."
msgstr ""
#: lib/web/templates/api/terms.html.heex:55
#, elixir-autogen, elixir-format
msgctxt "terms"
msgid "When we say “we”, “our”, or “us” in this document, we are referring to the owners, operators and administrators of this Mobilizon instance. The Mobilizon software is provided by the team of Mobilizon contributors, supported by <a href=\"https://framasoft.org\">Framasoft</a>, a French not-for-profit organization advocating for Free/Libre Software. Unless explicitly stated, this Mobilizon instance is an independent service using Mobilizon's source code. You may find more information about this instance on the <a href=\"/about/instance\">\"About this instance\"</a> page."
msgstr ""
#: lib/web/templates/api/terms.html.heex:105
#, elixir-autogen, elixir-format
msgctxt "terms"
@ -1630,7 +1624,7 @@ msgstr ""
#: lib/web/templates/email/pending_participation_notification.html.heex:47
#: lib/web/templates/email/pending_participation_notification.text.eex:4
#, elixir-format
#, elixir-format, elixir-autogen
msgid "You have one pending attendance request to process for the following event:"
msgid_plural "You have %{number_participation_requests} attendance requests to process for the following event:"
msgstr[0] ""
@ -2025,3 +2019,9 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "Well done!"
msgstr ""
#: lib/web/templates/api/terms.html.heex:55
#, elixir-autogen, elixir-format, fuzzy
msgctxt "terms"
msgid "When we say “we”, “our”, or “us” in this document, we are referring to the owners, operators and administrators of this Mobilizon instance. The Mobilizon software is provided by the team of Mobilizon contributors. Unless explicitly stated, this Mobilizon instance is an independent service using Mobilizon's source code. You may find more information about this instance on the <a href=\"/about/instance\">\"About this instance\"</a> page."
msgstr ""

View file

@ -181,13 +181,13 @@ msgstr ""
msgid "The current password is invalid"
msgstr ""
#: lib/graphql/resolvers/admin.ex:334
#: lib/graphql/resolvers/admin.ex:335
#: lib/graphql/resolvers/user.ex:527
#, elixir-autogen, elixir-format
msgid "The new email doesn't seem to be valid"
msgstr ""
#: lib/graphql/resolvers/admin.ex:323
#: lib/graphql/resolvers/admin.ex:324
#: lib/graphql/resolvers/user.ex:514
#, elixir-autogen, elixir-format
msgid "The new email must be different"
@ -621,7 +621,7 @@ msgstr ""
msgid "You don't have permission to delete this token"
msgstr ""
#: lib/graphql/resolvers/admin.ex:56
#: lib/graphql/resolvers/admin.ex:57
#, elixir-autogen, elixir-format
msgid "You need to be logged-in and a moderator to list action logs"
msgstr ""
@ -641,17 +641,17 @@ msgstr ""
msgid "You need to be logged-in and a moderator to view a report"
msgstr ""
#: lib/graphql/resolvers/admin.ex:258
#: lib/graphql/resolvers/admin.ex:259
#, elixir-autogen, elixir-format
msgid "You need to be logged-in and an administrator to access admin settings"
msgstr ""
#: lib/graphql/resolvers/admin.ex:242
#: lib/graphql/resolvers/admin.ex:243
#, elixir-autogen, elixir-format
msgid "You need to be logged-in and an administrator to access dashboard statistics"
msgstr ""
#: lib/graphql/resolvers/admin.ex:283
#: lib/graphql/resolvers/admin.ex:284
#, elixir-autogen, elixir-format
msgid "You need to be logged-in and an administrator to save admin settings"
msgstr ""
@ -938,7 +938,7 @@ msgstr ""
msgid "Failed to update the group"
msgstr ""
#: lib/graphql/resolvers/admin.ex:357
#: lib/graphql/resolvers/admin.ex:358
#: lib/graphql/resolvers/user.ex:547
#, elixir-autogen, elixir-format
msgid "Failed to update user email"
@ -1069,22 +1069,22 @@ msgstr ""
msgid "Your email seems to be using an invalid format"
msgstr ""
#: lib/graphql/resolvers/admin.ex:399
#: lib/graphql/resolvers/admin.ex:400
#, elixir-autogen, elixir-format
msgid "Can't confirm an already confirmed user"
msgstr ""
#: lib/graphql/resolvers/admin.ex:403
#: lib/graphql/resolvers/admin.ex:404
#, elixir-autogen, elixir-format
msgid "Deconfirming users is not supported"
msgstr ""
#: lib/graphql/resolvers/admin.ex:375
#: lib/graphql/resolvers/admin.ex:376
#, elixir-autogen, elixir-format, fuzzy
msgid "The new role must be different"
msgstr ""
#: lib/graphql/resolvers/admin.ex:314
#: lib/graphql/resolvers/admin.ex:315
#, elixir-autogen, elixir-format, fuzzy
msgid "You need to be logged-in and an administrator to edit an user's details"
msgstr ""
@ -1094,7 +1094,7 @@ msgstr ""
msgid "A profile or group with that name already exists"
msgstr ""
#: lib/graphql/resolvers/admin.ex:542
#: lib/graphql/resolvers/admin.ex:560
#, elixir-autogen, elixir-format
msgid "Unable to find an instance to follow at this address"
msgstr ""
@ -1356,7 +1356,7 @@ msgstr ""
msgid "The same push subscription has already been registered"
msgstr ""
#: lib/graphql/resolvers/admin.ex:536
#: lib/graphql/resolvers/admin.ex:554
#, elixir-autogen, elixir-format
msgid "This instance is pending follow approval"
msgstr ""
@ -1366,7 +1366,7 @@ msgstr ""
msgid "Timezone ID %{timezone} is invalid"
msgstr ""
#: lib/graphql/resolvers/admin.ex:539
#: lib/graphql/resolvers/admin.ex:557
#, elixir-autogen, elixir-format, fuzzy
msgid "You are already following this instance"
msgstr ""
@ -1386,12 +1386,12 @@ msgstr ""
msgid "The token you provided is invalid. Make sure that the URL is exactly the one provided inside the email you got."
msgstr ""
#: lib/graphql/resolvers/conversation.ex:161
#: lib/graphql/resolvers/conversation.ex:164
#, elixir-autogen, elixir-format
msgid "Conversation needs to mention at least one participant that's not yourself"
msgstr ""
#: lib/graphql/resolvers/participant.ex:396
#: lib/graphql/resolvers/participant.ex:401
#, elixir-autogen, elixir-format
msgid "There are no participants matching the audience you've selected."
msgstr ""

View file

@ -222,7 +222,7 @@ msgstr ""
#: lib/web/templates/email/email_direct_activity.html.heex:230
#: lib/web/templates/email/email_direct_activity.text.eex:23
#, elixir-format
#, elixir-format, elixir-autogen
msgid "View one more activity"
msgid_plural "View %{count} more activities"
msgstr[0] ""
@ -232,7 +232,7 @@ msgstr[1] ""
#: lib/web/templates/email/email_direct_activity.html.heex:60
#: lib/web/templates/email/email_direct_activity.text.eex:6
#: lib/web/templates/email/email_direct_activity.text.eex:7
#, elixir-format
#, elixir-format, elixir-autogen
msgid "There has been an activity!"
msgid_plural "There has been some activity!"
msgstr[0] ""

View file

@ -358,7 +358,7 @@ msgid "Mobilizon on %{instance}: email changed"
msgstr "Mobilizon a %{instance}: s'ha canviat l'adreça de correu"
#: lib/web/email/notification.ex:52
#, elixir-format
#, elixir-format, elixir-autogen
msgid "One event planned today"
msgid_plural "%{nb_events} events planned today"
msgstr[0] "Una activitat planificada per avui"
@ -366,7 +366,7 @@ msgstr[1] "%{nb_events} activitats planificades avui"
#: lib/web/templates/email/on_day_notification.html.heex:47
#: lib/web/templates/email/on_day_notification.text.eex:3
#, elixir-format
#, elixir-format, elixir-autogen
msgid "You have one event today:"
msgid_plural "You have %{total} events today:"
msgstr[0] "Tens una activitat avui:"
@ -416,14 +416,14 @@ msgid "You have been invited by %{inviter} to join group %{group}"
msgstr "%{inviter} t'ha convidat al grup %{group}"
#: lib/web/email/notification.ex:81
#, elixir-format
#, elixir-format, elixir-autogen
msgid "One event planned this week"
msgid_plural "%{nb_events} events planned this week"
msgstr[0] "Una activitat planificada per aquesta setmana"
msgstr[1] "%{nb_events} planificades per aquesta setmana"
#: lib/web/email/notification.ex:107
#, elixir-format
#, elixir-format, elixir-autogen
msgid "One participation request for event %{title} to process"
msgid_plural "%{number_participation_requests} participation requests for event %{title} to process"
msgstr[0] "Hi ha una soŀlicitud de participar a %{title} pendent de resoldre"
@ -433,7 +433,7 @@ msgstr[1] ""
#: lib/web/templates/email/notification_each_week.html.heex:47
#: lib/web/templates/email/notification_each_week.text.eex:3
#, elixir-format
#, elixir-format, elixir-autogen
msgid "You have one event this week:"
msgid_plural "You have %{total} events this week:"
msgstr[0] "Tens una activitat aquesta setmana:"
@ -925,7 +925,7 @@ msgstr "No ho facis servir més que proves, sisplau"
#: lib/web/templates/email/notification_each_week.text.eex:11
#: lib/web/templates/email/on_day_notification.html.heex:89
#: lib/web/templates/email/on_day_notification.text.eex:11
#, elixir-format
#, elixir-format, elixir-autogen
msgid "Would you wish to cancel your attendance, visit the event page through the link above and click the « Attending » button."
msgid_plural "Would you wish to cancel your attendance to one or several events, visit the event pages through the links above and click the « Attending » button."
msgstr[0] ""
@ -1261,7 +1261,7 @@ msgstr ""
"L'equip de moderació de la teva instància ha decidit suspendre el grup "
"%{group_name} (%{group_address}). Ja no formes part del grup."
#: lib/web/email/group.ex:108
#: lib/web/email/group.ex:106
#, elixir-autogen, elixir-format
msgid "The group %{group} has been suspended on %{instance}"
msgstr "El grup %{group} ha estat suspès a %{instance}"
@ -1375,12 +1375,6 @@ msgctxt "terms"
msgid "We reserve the right to modify these Terms at any time. For instance, we may need to change these Terms if we come out with a new feature."
msgstr ""
#: lib/web/templates/api/terms.html.heex:55
#, elixir-autogen, elixir-format
msgctxt "terms"
msgid "When we say “we”, “our”, or “us” in this document, we are referring to the owners, operators and administrators of this Mobilizon instance. The Mobilizon software is provided by the team of Mobilizon contributors, supported by <a href=\"https://framasoft.org\">Framasoft</a>, a French not-for-profit organization advocating for Free/Libre Software. Unless explicitly stated, this Mobilizon instance is an independent service using Mobilizon's source code. You may find more information about this instance on the <a href=\"/about/instance\">\"About this instance\"</a> page."
msgstr ""
#: lib/web/templates/api/terms.html.heex:105
#, elixir-autogen, elixir-format
msgctxt "terms"
@ -1876,7 +1870,7 @@ msgstr ""
#: lib/web/templates/email/pending_participation_notification.html.heex:47
#: lib/web/templates/email/pending_participation_notification.text.eex:4
#, elixir-format
#, elixir-format, elixir-autogen
msgid "You have one pending attendance request to process for the following event:"
msgid_plural "You have %{number_participation_requests} attendance requests to process for the following event:"
msgstr[0] "Tens una soŀlicitud de participació pendent de resoldre:"
@ -2283,3 +2277,9 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "Well done!"
msgstr ""
#: lib/web/templates/api/terms.html.heex:55
#, elixir-autogen, elixir-format, fuzzy
msgctxt "terms"
msgid "When we say “we”, “our”, or “us” in this document, we are referring to the owners, operators and administrators of this Mobilizon instance. The Mobilizon software is provided by the team of Mobilizon contributors. Unless explicitly stated, this Mobilizon instance is an independent service using Mobilizon's source code. You may find more information about this instance on the <a href=\"/about/instance\">\"About this instance\"</a> page."
msgstr ""

View file

@ -182,13 +182,13 @@ msgstr ""
msgid "The current password is invalid"
msgstr ""
#: lib/graphql/resolvers/admin.ex:334
#: lib/graphql/resolvers/admin.ex:335
#: lib/graphql/resolvers/user.ex:527
#, elixir-autogen, elixir-format
msgid "The new email doesn't seem to be valid"
msgstr ""
#: lib/graphql/resolvers/admin.ex:323
#: lib/graphql/resolvers/admin.ex:324
#: lib/graphql/resolvers/user.ex:514
#, elixir-autogen, elixir-format
msgid "The new email must be different"
@ -622,7 +622,7 @@ msgstr ""
msgid "You don't have permission to delete this token"
msgstr ""
#: lib/graphql/resolvers/admin.ex:56
#: lib/graphql/resolvers/admin.ex:57
#, elixir-autogen, elixir-format
msgid "You need to be logged-in and a moderator to list action logs"
msgstr ""
@ -642,17 +642,17 @@ msgstr ""
msgid "You need to be logged-in and a moderator to view a report"
msgstr ""
#: lib/graphql/resolvers/admin.ex:258
#: lib/graphql/resolvers/admin.ex:259
#, elixir-autogen, elixir-format
msgid "You need to be logged-in and an administrator to access admin settings"
msgstr ""
#: lib/graphql/resolvers/admin.ex:242
#: lib/graphql/resolvers/admin.ex:243
#, elixir-autogen, elixir-format
msgid "You need to be logged-in and an administrator to access dashboard statistics"
msgstr ""
#: lib/graphql/resolvers/admin.ex:283
#: lib/graphql/resolvers/admin.ex:284
#, elixir-autogen, elixir-format
msgid "You need to be logged-in and an administrator to save admin settings"
msgstr ""
@ -939,7 +939,7 @@ msgstr ""
msgid "Failed to update the group"
msgstr ""
#: lib/graphql/resolvers/admin.ex:357
#: lib/graphql/resolvers/admin.ex:358
#: lib/graphql/resolvers/user.ex:547
#, elixir-autogen, elixir-format
msgid "Failed to update user email"
@ -1070,22 +1070,22 @@ msgstr ""
msgid "Your email seems to be using an invalid format"
msgstr ""
#: lib/graphql/resolvers/admin.ex:399
#: lib/graphql/resolvers/admin.ex:400
#, elixir-autogen, elixir-format
msgid "Can't confirm an already confirmed user"
msgstr ""
#: lib/graphql/resolvers/admin.ex:403
#: lib/graphql/resolvers/admin.ex:404
#, elixir-autogen, elixir-format
msgid "Deconfirming users is not supported"
msgstr ""
#: lib/graphql/resolvers/admin.ex:375
#: lib/graphql/resolvers/admin.ex:376
#, elixir-autogen, elixir-format, fuzzy
msgid "The new role must be different"
msgstr ""
#: lib/graphql/resolvers/admin.ex:314
#: lib/graphql/resolvers/admin.ex:315
#, elixir-autogen, elixir-format, fuzzy
msgid "You need to be logged-in and an administrator to edit an user's details"
msgstr ""
@ -1095,7 +1095,7 @@ msgstr ""
msgid "A profile or group with that name already exists"
msgstr ""
#: lib/graphql/resolvers/admin.ex:542
#: lib/graphql/resolvers/admin.ex:560
#, elixir-autogen, elixir-format
msgid "Unable to find an instance to follow at this address"
msgstr ""
@ -1357,7 +1357,7 @@ msgstr ""
msgid "The same push subscription has already been registered"
msgstr ""
#: lib/graphql/resolvers/admin.ex:536
#: lib/graphql/resolvers/admin.ex:554
#, elixir-autogen, elixir-format
msgid "This instance is pending follow approval"
msgstr ""
@ -1367,7 +1367,7 @@ msgstr ""
msgid "Timezone ID %{timezone} is invalid"
msgstr ""
#: lib/graphql/resolvers/admin.ex:539
#: lib/graphql/resolvers/admin.ex:557
#, elixir-autogen, elixir-format, fuzzy
msgid "You are already following this instance"
msgstr ""
@ -1387,12 +1387,12 @@ msgstr ""
msgid "The token you provided is invalid. Make sure that the URL is exactly the one provided inside the email you got."
msgstr ""
#: lib/graphql/resolvers/conversation.ex:161
#: lib/graphql/resolvers/conversation.ex:164
#, elixir-autogen, elixir-format
msgid "Conversation needs to mention at least one participant that's not yourself"
msgstr ""
#: lib/graphql/resolvers/participant.ex:396
#: lib/graphql/resolvers/participant.ex:401
#, elixir-autogen, elixir-format
msgid "There are no participants matching the audience you've selected."
msgstr ""

View file

@ -224,7 +224,7 @@ msgstr ""
#: lib/web/templates/email/email_direct_activity.html.heex:230
#: lib/web/templates/email/email_direct_activity.text.eex:23
#, elixir-format
#, elixir-format, elixir-autogen
msgid "View one more activity"
msgid_plural "View %{count} more activities"
msgstr[0] "Zobrazit jednu další aktivitu"
@ -235,7 +235,7 @@ msgstr[2] "Zobrazit %{count} dalších aktivit"
#: lib/web/templates/email/email_direct_activity.html.heex:60
#: lib/web/templates/email/email_direct_activity.text.eex:6
#: lib/web/templates/email/email_direct_activity.text.eex:7
#, elixir-format
#, elixir-format, elixir-autogen
msgid "There has been an activity!"
msgid_plural "There has been some activity!"
msgstr[0] "Došlo k aktivitě!"

View file

@ -355,7 +355,7 @@ msgid "Mobilizon on %{instance}: email changed"
msgstr "Mobilizon na %{instance}: e-mail změněn"
#: lib/web/email/notification.ex:52
#, elixir-format
#, elixir-format, elixir-autogen
msgid "One event planned today"
msgid_plural "%{nb_events} events planned today"
msgstr[0] "Na dnešek je naplánována jedna událost"
@ -364,7 +364,7 @@ msgstr[2] "%{nb_events} událostí plánovaných na dnešek"
#: lib/web/templates/email/on_day_notification.html.heex:47
#: lib/web/templates/email/on_day_notification.text.eex:3
#, elixir-format
#, elixir-format, elixir-autogen
msgid "You have one event today:"
msgid_plural "You have %{total} events today:"
msgstr[0] "Dnes máte jednu událost:"
@ -415,7 +415,7 @@ msgid "You have been invited by %{inviter} to join group %{group}"
msgstr "Byl/a jste pozván/a %{inviter} do skupiny %{group}"
#: lib/web/email/notification.ex:81
#, elixir-format
#, elixir-format, elixir-autogen
msgid "One event planned this week"
msgid_plural "%{nb_events} events planned this week"
msgstr[0] "Tento týden je naplánována jedna akce"
@ -423,7 +423,7 @@ msgstr[1] "%{nb_events} události plánované na tento týden"
msgstr[2] "%{nb_events} událostí plánovaných na tento týden"
#: lib/web/email/notification.ex:107
#, elixir-format
#, elixir-format, elixir-autogen
msgid "One participation request for event %{title} to process"
msgid_plural "%{number_participation_requests} participation requests for event %{title} to process"
msgstr[0] "Jeden požadavek na účast pro událost %{title} ke zpracování"
@ -436,7 +436,7 @@ msgstr[2] ""
#: lib/web/templates/email/notification_each_week.html.heex:47
#: lib/web/templates/email/notification_each_week.text.eex:3
#, elixir-format
#, elixir-format, elixir-autogen
msgid "You have one event this week:"
msgid_plural "You have %{total} events this week:"
msgstr[0] "Tento týden máte jednu událost:"
@ -932,7 +932,7 @@ msgstr "Nepoužívejte ji pro skutečné účely."
#: lib/web/templates/email/notification_each_week.text.eex:11
#: lib/web/templates/email/on_day_notification.html.heex:89
#: lib/web/templates/email/on_day_notification.text.eex:11
#, elixir-format
#, elixir-format, elixir-autogen
msgid "Would you wish to cancel your attendance, visit the event page through the link above and click the « Attending » button."
msgid_plural "Would you wish to cancel your attendance to one or several events, visit the event pages through the links above and click the « Attending » button."
msgstr[0] ""
@ -1278,7 +1278,7 @@ msgstr ""
"Moderátorský tým vaší instance se rozhodl pozastavit %{group_name} "
"(%{group_address}). Již nejste členem této skupiny."
#: lib/web/email/group.ex:108
#: lib/web/email/group.ex:106
#, elixir-autogen, elixir-format
msgid "The group %{group} has been suspended on %{instance}"
msgstr "Skupina %{group} byla pozastavena na %{instance}"
@ -1403,20 +1403,6 @@ msgstr ""
"Vyhrazujeme si právo tyto podmínky kdykoli změnit. Tyto podmínky můžeme "
"například změnit, pokud přijdeme s novou funkcí."
#: lib/web/templates/api/terms.html.heex:55
#, elixir-autogen, elixir-format
msgctxt "terms"
msgid "When we say “we”, “our”, or “us” in this document, we are referring to the owners, operators and administrators of this Mobilizon instance. The Mobilizon software is provided by the team of Mobilizon contributors, supported by <a href=\"https://framasoft.org\">Framasoft</a>, a French not-for-profit organization advocating for Free/Libre Software. Unless explicitly stated, this Mobilizon instance is an independent service using Mobilizon's source code. You may find more information about this instance on the <a href=\"/about/instance\">\"About this instance\"</a> page."
msgstr ""
"Když v tomto dokumentu říkáme \"my\", \"naše\" nebo \"nás\", máme na mysli "
"vlastníky, provozovatele a správce této instance Mobilizon. Software "
"Mobilizon je poskytován týmem přispěvatelů Mobilizonu, který je podporován "
"<a href=\"https://framasoft.org\">Framasoft</a>, francouzskou neziskovou "
"organizací prosazující svobodný software. Pokud to není výslovně uvedeno, je "
"tato instance Mobilizonu nezávislou službou využívající zdrojový kód "
"Mobilizonu. Více informací o této instanci najdete na stránce <a href=\"/"
"about/instance\">\"O této instanci\"</a>."
#: lib/web/templates/api/terms.html.heex:105
#, elixir-autogen, elixir-format
msgctxt "terms"
@ -1945,7 +1931,7 @@ msgstr ""
#: lib/web/templates/email/pending_participation_notification.html.heex:47
#: lib/web/templates/email/pending_participation_notification.text.eex:4
#, elixir-format
#, elixir-format, elixir-autogen
msgid "You have one pending attendance request to process for the following event:"
msgid_plural "You have %{number_participation_requests} attendance requests to process for the following event:"
msgstr[0] ""
@ -2376,3 +2362,17 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "Well done!"
msgstr ""
#: lib/web/templates/api/terms.html.heex:55
#, elixir-autogen, elixir-format, fuzzy
msgctxt "terms"
msgid "When we say “we”, “our”, or “us” in this document, we are referring to the owners, operators and administrators of this Mobilizon instance. The Mobilizon software is provided by the team of Mobilizon contributors. Unless explicitly stated, this Mobilizon instance is an independent service using Mobilizon's source code. You may find more information about this instance on the <a href=\"/about/instance\">\"About this instance\"</a> page."
msgstr ""
"Když v tomto dokumentu říkáme \"my\", \"naše\" nebo \"nás\", máme na mysli "
"vlastníky, provozovatele a správce této instance Mobilizon. Software "
"Mobilizon je poskytován týmem přispěvatelů Mobilizonu, který je podporován "
"<a href=\"https://framasoft.org\">Framasoft</a>, francouzskou neziskovou "
"organizací prosazující svobodný software. Pokud to není výslovně uvedeno, je "
"tato instance Mobilizonu nezávislou službou využívající zdrojový kód "
"Mobilizonu. Více informací o této instanci najdete na stránce <a href=\"/"
"about/instance\">\"O této instanci\"</a>."

View file

@ -190,13 +190,13 @@ msgstr "Registrace nejsou otevřeny"
msgid "The current password is invalid"
msgstr "Aktuální heslo je neplatné"
#: lib/graphql/resolvers/admin.ex:334
#: lib/graphql/resolvers/admin.ex:335
#: lib/graphql/resolvers/user.ex:527
#, elixir-autogen, elixir-format
msgid "The new email doesn't seem to be valid"
msgstr "Nový e-mail se nezdá být platný"
#: lib/graphql/resolvers/admin.ex:323
#: lib/graphql/resolvers/admin.ex:324
#: lib/graphql/resolvers/user.ex:514
#, elixir-autogen, elixir-format
msgid "The new email must be different"
@ -635,7 +635,7 @@ msgstr "Do této skupiny nelze zvát"
msgid "You don't have permission to delete this token"
msgstr "Nemáte oprávnění tento token odstranit"
#: lib/graphql/resolvers/admin.ex:56
#: lib/graphql/resolvers/admin.ex:57
#, elixir-autogen, elixir-format
msgid "You need to be logged-in and a moderator to list action logs"
msgstr ""
@ -656,19 +656,19 @@ msgstr "Chcete-li aktualizovat zprávu, musíte být přihlášeni a být moder
msgid "You need to be logged-in and a moderator to view a report"
msgstr "Pro zobrazení zprávy musíte být přihlášeni a být moderátorem"
#: lib/graphql/resolvers/admin.ex:258
#: lib/graphql/resolvers/admin.ex:259
#, elixir-autogen, elixir-format
msgid "You need to be logged-in and an administrator to access admin settings"
msgstr "Pro přístup k nastavení správce musíte být přihlášeni jako správce"
#: lib/graphql/resolvers/admin.ex:242
#: lib/graphql/resolvers/admin.ex:243
#, elixir-autogen, elixir-format
msgid "You need to be logged-in and an administrator to access dashboard statistics"
msgstr ""
"Pro přístup ke statistikám ovládacího panelu musíte být přihlášeni jako "
"správce"
#: lib/graphql/resolvers/admin.ex:283
#: lib/graphql/resolvers/admin.ex:284
#, elixir-autogen, elixir-format
msgid "You need to be logged-in and an administrator to save admin settings"
msgstr ""
@ -959,7 +959,7 @@ msgstr "Nepodařilo se opustit událost"
msgid "Failed to update the group"
msgstr "Nepodařilo se aktualizovat skupinu"
#: lib/graphql/resolvers/admin.ex:357
#: lib/graphql/resolvers/admin.ex:358
#: lib/graphql/resolvers/user.ex:547
#, elixir-autogen, elixir-format
msgid "Failed to update user email"
@ -1090,22 +1090,22 @@ msgstr "Chcete-li odebrat člena, musíte být přihlášeni"
msgid "Your email seems to be using an invalid format"
msgstr "Váš e-mail zřejmě používá nesprávný formát"
#: lib/graphql/resolvers/admin.ex:399
#: lib/graphql/resolvers/admin.ex:400
#, elixir-autogen, elixir-format
msgid "Can't confirm an already confirmed user"
msgstr "Nelze potvrdit již potvrzeného uživatele"
#: lib/graphql/resolvers/admin.ex:403
#: lib/graphql/resolvers/admin.ex:404
#, elixir-autogen, elixir-format
msgid "Deconfirming users is not supported"
msgstr "Zrušení potvrzení uživatelů není podporováno"
#: lib/graphql/resolvers/admin.ex:375
#: lib/graphql/resolvers/admin.ex:376
#, elixir-autogen, elixir-format
msgid "The new role must be different"
msgstr "Nová role musí být jiná"
#: lib/graphql/resolvers/admin.ex:314
#: lib/graphql/resolvers/admin.ex:315
#, elixir-autogen, elixir-format
msgid "You need to be logged-in and an administrator to edit an user's details"
msgstr ""
@ -1116,7 +1116,7 @@ msgstr ""
msgid "A profile or group with that name already exists"
msgstr "Profil nebo skupina s tímto názvem již existuje"
#: lib/graphql/resolvers/admin.ex:542
#: lib/graphql/resolvers/admin.ex:560
#, elixir-autogen, elixir-format
msgid "Unable to find an instance to follow at this address"
msgstr ""
@ -1389,7 +1389,7 @@ msgstr ""
msgid "The same push subscription has already been registered"
msgstr ""
#: lib/graphql/resolvers/admin.ex:536
#: lib/graphql/resolvers/admin.ex:554
#, elixir-autogen, elixir-format
msgid "This instance is pending follow approval"
msgstr ""
@ -1399,7 +1399,7 @@ msgstr ""
msgid "Timezone ID %{timezone} is invalid"
msgstr ""
#: lib/graphql/resolvers/admin.ex:539
#: lib/graphql/resolvers/admin.ex:557
#, elixir-autogen, elixir-format, fuzzy
msgid "You are already following this instance"
msgstr "Tuto skupinu již sledujete"
@ -1419,12 +1419,12 @@ msgstr ""
msgid "The token you provided is invalid. Make sure that the URL is exactly the one provided inside the email you got."
msgstr ""
#: lib/graphql/resolvers/conversation.ex:161
#: lib/graphql/resolvers/conversation.ex:164
#, elixir-autogen, elixir-format
msgid "Conversation needs to mention at least one participant that's not yourself"
msgstr ""
#: lib/graphql/resolvers/participant.ex:396
#: lib/graphql/resolvers/participant.ex:401
#, elixir-autogen, elixir-format
msgid "There are no participants matching the audience you've selected."
msgstr ""

View file

@ -8,15 +8,15 @@
## to merge POT files into PO files.
msgid ""
msgstr ""
"PO-Revision-Date: 2023-10-14 00:00+0000\n"
"Last-Translator: Vri <vrifox@vrifox.cc>\n"
"PO-Revision-Date: 2024-04-12 14:40+0000\n"
"Last-Translator: Samuel Brinkmann <sbrinkmann@54gradsoftware.de>\n"
"Language-Team: German <https://weblate.framasoft.org/projects/mobilizon/"
"activity/de/>\n"
"Language: de\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.0.1\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Weblate 5.4.3\n"
#: lib/web/templates/email/activity/_member_activity_item.html.heex:14
#: lib/web/templates/email/activity/_member_activity_item.text.eex:12
@ -228,7 +228,7 @@ msgstr ""
#: lib/web/templates/email/email_direct_activity.html.heex:230
#: lib/web/templates/email/email_direct_activity.text.eex:23
#, elixir-format
#, elixir-format, elixir-autogen
msgid "View one more activity"
msgid_plural "View %{count} more activities"
msgstr[0] "%{count} weitere Aktivität anzeigen"
@ -238,7 +238,7 @@ msgstr[1] "Eine weitere Aktivität anzeigen"
#: lib/web/templates/email/email_direct_activity.html.heex:60
#: lib/web/templates/email/email_direct_activity.text.eex:6
#: lib/web/templates/email/email_direct_activity.text.eex:7
#, elixir-format
#, elixir-format, elixir-autogen
msgid "There has been an activity!"
msgid_plural "There has been some activity!"
msgstr[0] "Es hat sich etwas getan!"
@ -502,10 +502,10 @@ msgstr "Ein anonymes Profil"
#: lib/web/templates/email/email_anonymous_activity.html.heex:107
#: lib/web/templates/email/email_anonymous_activity.text.eex:14
#, elixir-autogen, elixir-format, fuzzy
#, elixir-autogen, elixir-format
msgid "%{profile} has posted a private announcement about event %{event}."
msgstr ""
"%{profile} hat eine Ankündigung unter der Veranstaltung %{event} "
"%{profile} hat eine private Ankündigung zur Veranstaltung %{event} "
"veröffentlicht."
#: lib/web/templates/email/email_anonymous_activity.html.heex:50

Some files were not shown because too many files have changed in this diff Show more