Revert "Merge remote-tracking branch 'origin/main' into fomo-v4.x"
This reverts commit4f32ebb940
, reversing changes made to6bee508b54
.
|
@ -1,14 +1,20 @@
|
|||
|
||||
155A1FB53DE39EC8EFCFD7FB94EA823D
|
||||
1C29EE70E90ECED01AF28EC58D2575B5
|
||||
26ED12A8E03D044BEDC08749BAA5E357
|
||||
2BB1D36656B423758A470021718FCB09
|
||||
31CE26BC979C57B9E3CC97B40C290CE5
|
||||
3529E7A4CECC24D02678820E6F521162
|
||||
3644C4E850300482AA409471EFE1EFB3
|
||||
4E7C044C59E0BCB76AA826789998F624
|
||||
53CBBEB6243FAF5C37249CBA17DE6F4C
|
||||
5BCE3651A03711295046DE48BDFE007E
|
||||
5C4CED447689F00D9D1ACEB9B895ED29
|
||||
5D8350E7A2DE5BB1CBCC983AF121F0DA
|
||||
94ACF7B17C3FF42F64E57DD1DA936BD8
|
||||
A32E125003F1EDFAD95C487C6A969725
|
||||
ACF6272A1DBB3A2ABD96C0C120B5CA69
|
||||
C46C4893B2F702ACADC4CAA5683FE370
|
||||
CD4CD6571816FCAF1E305066CDA0CD2F
|
||||
CDF2CCE0CF10F49CDFAE22FE26208155
|
||||
E720CB13C50FF3ADEE7C522531E11217
|
||||
F3D5851D3FB050939841ED2F14307A27
|
||||
FD1C9756370A195B74E95CE504C45E9E
|
|
@ -1,3 +1,2 @@
|
|||
erlang 26.2.2
|
||||
elixir 1.16.1-otp-26
|
||||
nodejs 18.19.1
|
||||
|
|
4
Makefile
|
@ -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"
|
||||
|
|
|
@ -36,7 +36,6 @@ config :mobilizon, :instance,
|
|||
unconfirmed_user_grace_period_hours: 48,
|
||||
activity_expire_days: 365,
|
||||
activity_keep_number: 100,
|
||||
duration_of_long_event: 30,
|
||||
enable_instance_feeds: true,
|
||||
email_from: "noreply@localhost",
|
||||
email_reply_to: "noreply@localhost"
|
||||
|
|
|
@ -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", "localhost"),
|
||||
port: String.to_integer(System.get_env("MOBILIZON_INSTANCE_HOST_PORT", "4000")),
|
||||
scheme: System.get_env("MOBILIZON_INSTANCE_SCHEME", "http")
|
||||
host: System.get_env("MOBILIZON_INSTANCE_HOST", "mobilizon.local"),
|
||||
port: String.to_integer(System.get_env("MOBILIZON_INSTANCE_HOST_PORT", "80")),
|
||||
scheme: "http"
|
||||
],
|
||||
secret_key_base: System.get_env("MOBILIZON_INSTANCE_SECRET_KEY_BASE", "changethis"),
|
||||
debug_errors: true,
|
||||
|
|
|
@ -149,38 +149,51 @@ geospatial_service =
|
|||
"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)
|
||||
if System.get_env("MOBILIZON_GEOSPATIAL_SERVICE", "Nominatim") == "Nominatim" do
|
||||
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)
|
||||
end
|
||||
|
||||
config :mobilizon, Mobilizon.Service.Geospatial.Addok,
|
||||
endpoint:
|
||||
System.get_env("MOBILIZON_GEOSPATIAL_ADDOK_ENDPOINT", "https://api-adresse.data.gouv.fr")
|
||||
if System.get_env("MOBILIZON_GEOSPATIAL_SERVICE", "Nominatim") == "Addok" do
|
||||
config :mobilizon, Mobilizon.Service.Geospatial.Addok,
|
||||
endpoint:
|
||||
System.get_env("MOBILIZON_GEOSPATIAL_ADDOK_ENDPOINT", "https://api-adresse.data.gouv.fr")
|
||||
end
|
||||
|
||||
config :mobilizon, Mobilizon.Service.Geospatial.Photon,
|
||||
endpoint: System.get_env("MOBILIZON_GEOSPATIAL_PHOTON_ENDPOINT", "https://photon.komoot.de")
|
||||
if System.get_env("MOBILIZON_GEOSPATIAL_SERVICE", "Nominatim") == "Photon" do
|
||||
config :mobilizon, Mobilizon.Service.Geospatial.Photon,
|
||||
endpoint: System.get_env("MOBILIZON_GEOSPATIAL_PHOTON_ENDPOINT", "https://photon.komoot.de")
|
||||
end
|
||||
|
||||
config :mobilizon, Mobilizon.Service.Geospatial.GoogleMaps,
|
||||
api_key: System.get_env("MOBILIZON_GEOSPATIAL_GOOGLE_MAPS_API_KEY", nil),
|
||||
fetch_place_details: true
|
||||
if System.get_env("MOBILIZON_GEOSPATIAL_SERVICE", "Nominatim") == "GoogleMaps" do
|
||||
config :mobilizon, Mobilizon.Service.Geospatial.GoogleMaps,
|
||||
api_key: System.get_env("MOBILIZON_GEOSPATIAL_GOOGLE_MAPS_API_KEY", nil),
|
||||
fetch_place_details: true
|
||||
end
|
||||
|
||||
config :mobilizon, Mobilizon.Service.Geospatial.MapQuest,
|
||||
api_key: System.get_env("MOBILIZON_GEOSPATIAL_MAP_QUEST_API_KEY", nil)
|
||||
if System.get_env("MOBILIZON_GEOSPATIAL_SERVICE", "Nominatim") == "MapQuest" do
|
||||
config :mobilizon, Mobilizon.Service.Geospatial.MapQuest,
|
||||
api_key: System.get_env("MOBILIZON_GEOSPATIAL_MAP_QUEST_API_KEY", nil)
|
||||
end
|
||||
|
||||
config :mobilizon, Mobilizon.Service.Geospatial.Mimirsbrunn,
|
||||
endpoint: System.get_env("MOBILIZON_GEOSPATIAL_MIMIRSBRUNN_ENDPOINT", nil)
|
||||
if System.get_env("MOBILIZON_GEOSPATIAL_SERVICE", "Nominatim") == "Mimirsbrunn" do
|
||||
config :mobilizon, Mobilizon.Service.Geospatial.Mimirsbrunn,
|
||||
endpoint: System.get_env("MOBILIZON_GEOSPATIAL_MIMIRSBRUNN_ENDPOINT", nil)
|
||||
end
|
||||
|
||||
config :mobilizon, Mobilizon.Service.Geospatial.Pelias,
|
||||
endpoint: System.get_env("MOBILIZON_GEOSPATIAL_PELIAS_ENDPOINT", nil)
|
||||
if System.get_env("MOBILIZON_GEOSPATIAL_SERVICE", "Nominatim") == "Pelias" do
|
||||
config :mobilizon, Mobilizon.Service.Geospatial.Pelias,
|
||||
endpoint: System.get_env("MOBILIZON_GEOSPATIAL_PELIAS_ENDPOINT", nil)
|
||||
end
|
||||
|
||||
sentry_dsn = System.get_env("MOBILIZON_ERROR_REPORTING_SENTRY_DSN", nil)
|
||||
|
||||
|
|
|
@ -2,8 +2,7 @@ import Config
|
|||
|
||||
config :mobilizon, :instance,
|
||||
name: "Test instance",
|
||||
registrations_open: true,
|
||||
duration_of_long_event: 0
|
||||
registrations_open: true
|
||||
|
||||
# We don't run a server during test. If one is required,
|
||||
# you can enable the server option below.
|
||||
|
|
125
default.nix
|
@ -1,35 +1,43 @@
|
|||
{
|
||||
lib,
|
||||
beam_nox,
|
||||
fetchFromGitHub,
|
||||
cmake,
|
||||
nixosTests,
|
||||
src,
|
||||
src-config,
|
||||
mobilizon-js,
|
||||
{ lib
|
||||
, beamPackages
|
||||
, fetchFromGitHub
|
||||
, git
|
||||
, cmake
|
||||
, nixosTests
|
||||
, src
|
||||
, src-config
|
||||
, mobilizon-js
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (beam_nox.packages.erlang) mixRelease buildMix elixir;
|
||||
inherit (beamPackages) mixRelease buildMix;
|
||||
in
|
||||
mixRelease rec {
|
||||
pname = "mobilizon";
|
||||
|
||||
# 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";
|
||||
version = "4.1.0";
|
||||
|
||||
inherit src;
|
||||
|
||||
# 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 ]; };
|
||||
# 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 ];
|
||||
};
|
||||
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.
|
||||
|
@ -37,27 +45,77 @@ 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 = "6e143dcde0a2854c4f0d72816b7ecab696432779";
|
||||
sha256 = "sha256-Da+/28SPZuUQBi8fQj31zmMvhMrYUaQIW4U4E+mRtMg=";
|
||||
};
|
||||
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 ];
|
||||
};
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
# fix elixir locale warning
|
||||
env.LANG = "C.UTF-8";
|
||||
preConfigure = ''
|
||||
export LANG=C.UTF-8 # fix elixir locale warning
|
||||
'';
|
||||
|
||||
# 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
|
||||
|
@ -73,15 +131,12 @@ mixRelease rec {
|
|||
ln -s ${ex_cldr.src}/priv/cldr/locales $out/lib/ex_cldr-${ex_cldr.version}/priv/cldr/locales
|
||||
'';
|
||||
|
||||
passthru.elixirPackage = elixir;
|
||||
passthru.elixirPackage = beamPackages.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 ];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -56,11 +56,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1726463316,
|
||||
"narHash": "sha256-gI9kkaH0ZjakJOKrdjaI/VbaMEo9qBbSUl93DnU7f4c=",
|
||||
"lastModified": 1718318537,
|
||||
"narHash": "sha256-4Zu0RYRcAY/VWuu6awwq4opuiD//ahpc2aFHg2CWqFY=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "99dc8785f6a0adac95f5e2ab05cc2e1bf666d172",
|
||||
"rev": "e9ee548d90ff586a6471b4ae80ae9cfcbceb3420",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
469
flake.nix
|
@ -8,27 +8,20 @@
|
|||
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.
|
||||
|
@ -62,6 +55,9 @@
|
|||
};
|
||||
|
||||
mobilizon-frontend =
|
||||
let
|
||||
nodejs = pkgs.nodejs-18_x;
|
||||
in
|
||||
napalm.legacyPackages."${system}".buildPackage
|
||||
(filter {
|
||||
root = ./.;
|
||||
|
@ -74,12 +70,9 @@
|
|||
] ++ unrelatedDirs;
|
||||
})
|
||||
{
|
||||
inherit (pkgs) nodejs;
|
||||
inherit 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: {
|
||||
|
@ -91,11 +84,17 @@
|
|||
};
|
||||
|
||||
default = self.packages."${system}".mobilizon;
|
||||
}
|
||||
);
|
||||
|
||||
devShells = forAllSystems (
|
||||
system:
|
||||
# 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};
|
||||
settingsFormat = pkgs.formats.elixirConf { };
|
||||
|
@ -105,19 +104,11 @@
|
|||
server = true;
|
||||
url.host = "mobilizon.dev";
|
||||
http = {
|
||||
ip = settingsFormat.lib.mkTuple [
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
1
|
||||
];
|
||||
ip = settingsFormat.lib.mkTuple [ 0 0 0 0 0 0 0 1 ];
|
||||
port = 4000;
|
||||
};
|
||||
secret_key_base = "2q/l1WDx3RQQy7gZ1k001//6nc66moWUEJQyGuMK/z3zPLYW6FYtIgCkUzGP0+X/";
|
||||
secret_key_base =
|
||||
"2q/l1WDx3RQQy7gZ1k001//6nc66moWUEJQyGuMK/z3zPLYW6FYtIgCkUzGP0+X/";
|
||||
};
|
||||
"Mobilizon.Web.Auth.Guardian" = {
|
||||
secret_key = "N8x7/tf0kInLFS2poO22g6OGPiMjSrDEhmk29nFqV35q7hQ0DtBt/cRYCsqBNp2L";
|
||||
|
@ -141,83 +132,73 @@
|
|||
};
|
||||
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 = [
|
||||
default =
|
||||
pkgs.mkShell {
|
||||
MIX_ENV = "dev";
|
||||
PGUSER = "mobilizon";
|
||||
PGDATABASE = "mobilizon";
|
||||
buildInputs =
|
||||
with pkgs; [
|
||||
elixir
|
||||
mix2nix
|
||||
cmake
|
||||
imagemagick
|
||||
nodejs
|
||||
inotify-tools
|
||||
(pkgs.writeShellApplication {
|
||||
name = "build";
|
||||
runtimeInputs = [ elixir nodejs ];
|
||||
text = ''
|
||||
mix deps.get
|
||||
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
|
||||
'';
|
||||
})
|
||||
];
|
||||
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
|
||||
'';
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
nixosModules.devSetup =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
nixosModules.devSetup = { config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.mobilizonDevEnvironment;
|
||||
in
|
||||
{
|
||||
|
||||
options.mobilizonDevEnvironment = {
|
||||
enable = lib.mkEnableOption (lib.mdDoc "development environment for Mobilizon");
|
||||
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";
|
||||
|
@ -247,10 +228,12 @@
|
|||
|
||||
};
|
||||
|
||||
overlays.default = final: prev: { inherit (self.packages."${prev.system}") mobilizon; };
|
||||
overlays.default = final: prev: {
|
||||
inherit (self.packages."${prev.system}") mobilizon;
|
||||
};
|
||||
|
||||
checks = forAllSystems (system: {
|
||||
inherit (self.packages.${system}) mobilizon;
|
||||
inherit (self.packages.${system}) mobilizon update;
|
||||
nixosTest =
|
||||
let
|
||||
pkgsMobilizon = import nixpkgs {
|
||||
|
@ -266,8 +249,7 @@
|
|||
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
|
||||
|
@ -275,187 +257,112 @@
|
|||
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 x16 \
|
||||
-gravity center \
|
||||
-crop 16x16+0+0 \
|
||||
-flatten \
|
||||
-colors 256 \
|
||||
-resize x${resize} \
|
||||
'${favicon}' \
|
||||
public/img/icons/favicon-16x16.png
|
||||
public/img/icons/${filename}
|
||||
|
||||
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";
|
||||
}
|
||||
];
|
||||
'')
|
||||
[
|
||||
{ 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);
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,10 +7,7 @@ in
|
|||
|
||||
{
|
||||
name = "mobilizon";
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
minijackson
|
||||
erictapen
|
||||
];
|
||||
meta.maintainers = with lib.maintainers; [ minijackson erictapen ];
|
||||
|
||||
nodes.server =
|
||||
{ pkgs, ... }:
|
||||
|
|
|
@ -7,7 +7,6 @@ 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,
|
||||
|
@ -96,16 +95,16 @@ defmodule Mobilizon.Federation.ActivityPub.Publisher do
|
|||
date: date
|
||||
})
|
||||
|
||||
headers = [
|
||||
{"Content-Type", "application/activity+json"},
|
||||
{"signature", signature},
|
||||
{"digest", digest},
|
||||
{"date", date}
|
||||
]
|
||||
|
||||
client = ActivityPubClient.client(headers: headers)
|
||||
|
||||
ActivityPubClient.post(client, inbox, json)
|
||||
Tesla.post(
|
||||
inbox,
|
||||
json,
|
||||
headers: [
|
||||
{"Content-Type", "application/activity+json"},
|
||||
{"signature", signature},
|
||||
{"digest", digest},
|
||||
{"date", date}
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
@spec convert_followers_in_recipients(list(String.t())) :: {list(String.t()), list(String.t())}
|
||||
|
|
|
@ -9,9 +9,13 @@ 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.
|
||||
"""
|
||||
|
@ -61,7 +65,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 RemoteMediaDownloaderClient.get(media_url) do
|
||||
case Tesla.get(media_url, opts: @http_options) do
|
||||
{:ok, %{body: body}} ->
|
||||
case Upload.store(%{body: body, name: name}) do
|
||||
{:ok, %{url: _url} = uploaded} ->
|
||||
|
|
|
@ -57,25 +57,15 @@ 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
|
||||
# case url
|
||||
if Map.has_key?(media, :url) do
|
||||
with uploaded when is_map(uploaded) <-
|
||||
media
|
||||
|> Map.get(:file)
|
||||
|> Utils.make_media_data(description: Map.get(media, :name)) do
|
||||
%{
|
||||
file: %{"url" => media.url, "name" => media.name},
|
||||
file: Map.take(uploaded, [:url, :name, :content_type, :size]),
|
||||
metadata: Map.take(uploaded, [:width, :height, :blurhash]),
|
||||
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
|
||||
|
||||
|
|
|
@ -5,10 +5,11 @@ defmodule Mobilizon.GraphQL.Resolvers.Admin do
|
|||
|
||||
import Mobilizon.Users.Guards
|
||||
|
||||
alias Mobilizon.{Actors, Admin, Config, Events, Instances, Media, Users}
|
||||
alias Mobilizon.{Actors, Admin, Config, Events, Instances, Users}
|
||||
alias Mobilizon.Actors.{Actor, Follower}
|
||||
alias Mobilizon.Admin.{ActionLog, Setting, SettingMedia}
|
||||
alias Mobilizon.Admin.{ActionLog, Setting}
|
||||
alias Mobilizon.Cldr.Language
|
||||
alias Mobilizon.Config
|
||||
alias Mobilizon.Discussions.Comment
|
||||
alias Mobilizon.Events.Event
|
||||
alias Mobilizon.Federation.ActivityPub.{Actions, Relay}
|
||||
|
@ -19,9 +20,6 @@ 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
|
||||
|
||||
|
@ -270,11 +268,8 @@ defmodule Mobilizon.GraphQL.Resolvers.Admin do
|
|||
with {:ok, res} <- Admin.save_settings("instance", args),
|
||||
res <-
|
||||
res
|
||||
|> Enum.map(fn {key, val} ->
|
||||
case val do
|
||||
%Setting{value: value} -> {key, Admin.get_setting_value(value)}
|
||||
%SettingMedia{media: media} -> {key, media}
|
||||
end
|
||||
|> Enum.map(fn {key, %Setting{value: value}} ->
|
||||
{key, Admin.get_setting_value(value)}
|
||||
end)
|
||||
|> Enum.into(%{}),
|
||||
:ok <- eventually_update_instance_actor(res) do
|
||||
|
@ -289,38 +284,6 @@ 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()}
|
||||
|
|
|
@ -5,11 +5,8 @@ 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.
|
||||
"""
|
||||
|
@ -34,16 +31,6 @@ 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()
|
||||
|
@ -107,15 +94,10 @@ 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?(),
|
||||
|
|
|
@ -69,31 +69,13 @@ 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, true)}
|
||||
{:ok, Events.list_events(page, limit, order_by, direction)}
|
||||
end
|
||||
|
||||
def list_events(_parent, %{page: _page, limit: _limit}, _resolution) do
|
||||
|
|
|
@ -18,10 +18,6 @@ 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}
|
||||
|
@ -137,10 +133,8 @@ defmodule Mobilizon.GraphQL.Resolvers.Media do
|
|||
|
||||
def user_size(_parent, _args, _resolution), do: {:error, :unauthenticated}
|
||||
|
||||
@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
|
||||
@spec transform_media(Media.t()) :: map()
|
||||
defp transform_media(%Media{id: id, file: file, metadata: metadata}) do
|
||||
%{
|
||||
name: file.name,
|
||||
url: file.url,
|
||||
|
|
|
@ -124,24 +124,6 @@ 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"
|
||||
)
|
||||
|
@ -430,25 +412,6 @@ 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")
|
||||
|
|
|
@ -31,7 +31,6 @@ 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")
|
||||
|
@ -60,17 +59,6 @@ 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",
|
||||
|
|
|
@ -263,10 +263,6 @@ 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")
|
||||
|
||||
|
@ -320,10 +316,6 @@ 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")
|
||||
|
||||
|
@ -375,13 +367,6 @@ 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")
|
||||
|
||||
|
@ -395,11 +380,6 @@ 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)
|
||||
|
|
|
@ -52,9 +52,8 @@ 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, :upload, description: "The media file")
|
||||
field(:file, non_null(: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
|
||||
|
|
|
@ -273,8 +273,6 @@ 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")
|
||||
|
||||
|
|
|
@ -9,8 +9,7 @@ defmodule Mobilizon.Admin do
|
|||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.{Admin, Users}
|
||||
alias Mobilizon.Admin.ActionLog
|
||||
alias Mobilizon.Admin.{Setting, SettingMedia}
|
||||
alias Mobilizon.Medias.Media
|
||||
alias Mobilizon.Admin.Setting
|
||||
alias Mobilizon.Storage.{Page, Repo}
|
||||
alias Mobilizon.Users.User
|
||||
|
||||
|
@ -79,47 +78,9 @@ defmodule Mobilizon.Admin do
|
|||
|
||||
defp stringify_struct(struct), do: struct
|
||||
|
||||
@spec get_all_admin_settings :: map()
|
||||
@spec get_all_admin_settings :: list(Setting.t())
|
||||
def get_all_admin_settings do
|
||||
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
|
||||
)
|
||||
Repo.all(Setting)
|
||||
end
|
||||
|
||||
@spec get_admin_setting_value(String.t(), String.t(), String.t() | nil) ::
|
||||
|
@ -158,40 +119,21 @@ 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_media_setting(group, medias)
|
||||
|> do_save_value_setting(group, values)
|
||||
|> do_save_setting(group, args)
|
||||
|> Repo.transaction()
|
||||
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
|
||||
def clear_settings(group) do
|
||||
Setting |> where([s], s.group == ^group) |> Repo.delete_all()
|
||||
end
|
||||
|
||||
defp do_save_value_setting(transaction, group, args) do
|
||||
@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
|
||||
key = hd(Map.keys(args))
|
||||
{val, rest} = Map.pop(args, key)
|
||||
|
||||
|
@ -208,40 +150,7 @@ defmodule Mobilizon.Admin do
|
|||
conflict_target: [:group, :name]
|
||||
)
|
||||
|
||||
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()
|
||||
do_save_setting(transaction, group, rest)
|
||||
end
|
||||
|
||||
@spec convert_to_string(any()) :: String.t()
|
||||
|
|
|
@ -4,7 +4,6 @@ defmodule Mobilizon.Admin.Setting do
|
|||
"""
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
alias Ecto.Changeset
|
||||
|
||||
@required_attrs [:group, :name]
|
||||
@optional_attrs [:value]
|
||||
|
@ -33,93 +32,3 @@ 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
|
||||
|
|
|
@ -4,8 +4,7 @@ defmodule Mobilizon.Config do
|
|||
"""
|
||||
|
||||
alias Mobilizon.Actors
|
||||
alias Mobilizon.Admin
|
||||
alias Mobilizon.Medias.Media
|
||||
alias Mobilizon.Admin.Setting
|
||||
alias Mobilizon.Service.GitStatus
|
||||
require Logger
|
||||
import Mobilizon.Service.Export.Participants.Common, only: [enabled_formats: 0]
|
||||
|
@ -31,18 +30,56 @@ 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 -> {:commit, Admin.get_all_admin_settings()} end
|
||||
) 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
|
||||
{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()
|
||||
|
@ -79,23 +116,10 @@ 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")
|
||||
def contact do
|
||||
config_cached_value("instance", "contact")
|
||||
end
|
||||
|
||||
@spec instance_terms(String.t()) :: String.t()
|
||||
def instance_terms(locale \\ "en") do
|
||||
|
@ -177,9 +201,6 @@ 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]
|
||||
|
||||
|
@ -448,9 +469,6 @@ 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(),
|
||||
|
|
|
@ -25,7 +25,6 @@ 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,
|
||||
|
@ -42,7 +41,6 @@ defmodule Mobilizon.Events.EventOptions do
|
|||
:program,
|
||||
:comment_moderation,
|
||||
:show_participation_price,
|
||||
:hide_number_of_participants,
|
||||
:show_start_time,
|
||||
:show_end_time,
|
||||
:timezone,
|
||||
|
@ -61,7 +59,6 @@ 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)
|
||||
|
|
|
@ -16,7 +16,6 @@ defmodule Mobilizon.Events do
|
|||
|
||||
alias Mobilizon.Actors.{Actor, Follower}
|
||||
alias Mobilizon.Addresses.Address
|
||||
alias Mobilizon.Config
|
||||
|
||||
alias Mobilizon.Events.{
|
||||
Event,
|
||||
|
@ -359,34 +358,19 @@ defmodule Mobilizon.Events do
|
|||
@doc """
|
||||
Returns the list of events.
|
||||
"""
|
||||
@spec list_events(
|
||||
integer | nil,
|
||||
integer | nil,
|
||||
atom,
|
||||
atom,
|
||||
boolean,
|
||||
boolean | nil,
|
||||
string | nil,
|
||||
float | nil
|
||||
) :: Page.t(Event.t())
|
||||
@spec list_events(integer | nil, integer | nil, atom, atom, boolean) :: Page.t(Event.t())
|
||||
def list_events(
|
||||
page \\ nil,
|
||||
limit \\ nil,
|
||||
sort \\ :begins_on,
|
||||
direction \\ :asc,
|
||||
is_future \\ true,
|
||||
longevents \\ nil,
|
||||
location \\ nil,
|
||||
radius \\ nil
|
||||
is_future \\ true
|
||||
) 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()
|
||||
|
@ -587,7 +571,6 @@ 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)
|
||||
|
@ -1394,36 +1377,6 @@ 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)
|
||||
|
|
|
@ -185,8 +185,7 @@ 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: "admin_settings_medias", param: "media_id"]
|
||||
[from: "comments_medias", param: "media_id"]
|
||||
]
|
||||
|> Enum.map_join(" UNION ", fn [from: from, param: param] ->
|
||||
"SELECT 1 FROM #{from} WHERE #{from}.#{param} = m0.id"
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
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
|
|
@ -1,58 +0,0 @@
|
|||
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
|
|
@ -18,7 +18,8 @@ defmodule Mobilizon.Web do
|
|||
"""
|
||||
|
||||
def static_paths,
|
||||
do: ~w(index.html service-worker.js css fonts img js robots.txt assets)
|
||||
do:
|
||||
~w(index.html manifest.json manifest.webmanifest service-worker.js css fonts img js favicon.ico robots.txt assets)
|
||||
|
||||
def controller do
|
||||
quote do
|
||||
|
|
|
@ -113,12 +113,6 @@ 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)
|
||||
|
|
|
@ -4,23 +4,21 @@
|
|||
<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={favicon_url()} sizes={favicon_sizes()} />
|
||||
<link rel="icon" href={favicon_url()} sizes={favicon_sizes()} />
|
||||
<link rel="apple-touch-icon" href="/img/icons/apple-touch-icon-152x152.png" sizes="152x152" />
|
||||
<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>
|
||||
<%= tags(assigns) || assigns.tags %>
|
||||
<%= Vite.vite_client() %>
|
||||
<%= Vite.vite_snippet("src/main.ts") %>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>
|
||||
|
|
|
@ -6,7 +6,6 @@ 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
|
||||
|
@ -92,27 +91,4 @@ 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
|
||||
|
|
6
mix.exs
|
@ -1,7 +1,7 @@
|
|||
defmodule Mobilizon.Mixfile do
|
||||
use Mix.Project
|
||||
|
||||
@version "5.0.0-beta.1"
|
||||
@version "4.1.0"
|
||||
|
||||
def project do
|
||||
[
|
||||
|
@ -240,9 +240,7 @@ 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]},
|
||||
# Generate nix dependencies
|
||||
{:deps_nix, "~> 0.0", only: :dev}
|
||||
{:credo_code_climate, "~> 0.1.0", only: [:dev, :test]}
|
||||
] ++ oauth_deps()
|
||||
end
|
||||
|
||||
|
|
9
mix.lock
|
@ -16,16 +16,15 @@
|
|||
"cors_plug": {:hex, :cors_plug, "3.0.3", "7c3ac52b39624bc616db2e937c282f3f623f25f8d550068b6710e58d04a0e330", [:mix], [{:plug, "~> 1.13", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "3f2d759e8c272ed3835fab2ef11b46bddab8c1ab9528167bd463b6452edf830d"},
|
||||
"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.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"},
|
||||
"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"},
|
||||
"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.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": {: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_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"},
|
||||
|
@ -79,7 +78,7 @@
|
|||
"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.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.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
|
||||
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
|
||||
"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"},
|
||||
|
@ -134,7 +133,7 @@
|
|||
"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.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"},
|
||||
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
|
||||
"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"},
|
||||
|
|
13
package-lock.json
generated
|
@ -1,12 +1,13 @@
|
|||
{
|
||||
"name": "mobilizon",
|
||||
"version": "5.0.0-beta.1",
|
||||
"version": "4.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "mobilizon",
|
||||
"version": "5.0.0-beta.1",
|
||||
"version": "4.1.0",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.9.5",
|
||||
"@framasoft/socket": "^1.0.0",
|
||||
|
@ -15,7 +16,7 @@
|
|||
"@fullcalendar/daygrid": "^6.1.10",
|
||||
"@fullcalendar/interaction": "^6.1.10",
|
||||
"@fullcalendar/vue3": "^6.1.10",
|
||||
"@oruga-ui/oruga-next": "0.8.12",
|
||||
"@oruga-ui/oruga-next": "^0.8.10",
|
||||
"@oruga-ui/theme-oruga": "^0.2.0",
|
||||
"@sentry/tracing": "^7.1",
|
||||
"@sentry/vue": "^7.1",
|
||||
|
@ -3138,9 +3139,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@oruga-ui/oruga-next": {
|
||||
"version": "0.8.12",
|
||||
"resolved": "https://registry.npmjs.org/@oruga-ui/oruga-next/-/oruga-next-0.8.12.tgz",
|
||||
"integrity": "sha512-I1jcsTA4J6HQdNpSWgK4cNSqv1cHsghQGtJ12p0yXDSJseek0Y8f4vf9+tDRtfONzWHuRyWUGcHIfePsRKVbiQ==",
|
||||
"version": "0.8.10",
|
||||
"resolved": "https://registry.npmjs.org/@oruga-ui/oruga-next/-/oruga-next-0.8.10.tgz",
|
||||
"integrity": "sha512-ETPSoGZu1parbj8C3V2ZojQnN4ptQMiJEwS9Hx44NcaDzu4q/FDsYkKYiz6G9kx8cDceXXxvydfOUpZePVVdzw==",
|
||||
"peerDependencies": {
|
||||
"vue": "^3.0.0"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "mobilizon",
|
||||
"version": "5.0.0-beta.1",
|
||||
"version": "4.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
@ -32,12 +32,12 @@
|
|||
"@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/interaction": "^6.1.10",
|
||||
"@fullcalendar/vue3": "^6.1.10",
|
||||
"@oruga-ui/oruga-next": "^0.8.10",
|
||||
"@oruga-ui/theme-oruga": "^0.2.0",
|
||||
"@sentry/tracing": "^7.1",
|
||||
"@sentry/vue": "^7.1",
|
||||
"@tiptap/core": "^2.0.0-beta.41",
|
||||
|
@ -145,8 +145,8 @@
|
|||
"sass": "^1.34.1",
|
||||
"typescript": "~5.3.2",
|
||||
"vite": "^5.0.12",
|
||||
"vite-svg-loader": "^4.0.0",
|
||||
"vite-plugin-pwa": "^0.19.0",
|
||||
"vite-svg-loader": "^4.0.0",
|
||||
"vitest": "^1.2.2",
|
||||
"vue-i18n-extract": "^2.0.4",
|
||||
"vue-router-mock": "^1.0.0"
|
||||
|
|
|
@ -8,15 +8,15 @@
|
|||
## to merge POT files into PO files.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2024-04-12 14:40+0000\n"
|
||||
"Last-Translator: Samuel Brinkmann <sbrinkmann@54gradsoftware.de>\n"
|
||||
"PO-Revision-Date: 2023-10-14 00:00+0000\n"
|
||||
"Last-Translator: Vri <vrifox@vrifox.cc>\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.4.3\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.0.1\n"
|
||||
|
||||
#: lib/web/templates/email/activity/_member_activity_item.html.heex:14
|
||||
#: lib/web/templates/email/activity/_member_activity_item.text.eex:12
|
||||
|
@ -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
|
||||
#, elixir-autogen, elixir-format, fuzzy
|
||||
msgid "%{profile} has posted a private announcement about event %{event}."
|
||||
msgstr ""
|
||||
"%{profile} hat eine private Ankündigung zur Veranstaltung %{event} "
|
||||
"%{profile} hat eine Ankündigung unter der Veranstaltung %{event} "
|
||||
"veröffentlicht."
|
||||
|
||||
#: lib/web/templates/email/email_anonymous_activity.html.heex:50
|
||||
|
|
|
@ -8,15 +8,16 @@
|
|||
## to merge POT files into PO files.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2024-04-16 17:29+0000\n"
|
||||
"Last-Translator: GSalinas <gsalinastellez@gmail.com>\n"
|
||||
"PO-Revision-Date: 2023-10-22 18:27+0000\n"
|
||||
"Last-Translator: Jaime Marquínez Ferrándiz <jaime.marquinez."
|
||||
"ferrandiz@fastmail.net>\n"
|
||||
"Language-Team: Spanish <https://weblate.framasoft.org/projects/mobilizon/"
|
||||
"activity/es/>\n"
|
||||
"Language: es\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.4.3\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.0.1\n"
|
||||
|
||||
#: lib/web/templates/email/activity/_member_activity_item.html.heex:14
|
||||
#: lib/web/templates/email/activity/_member_activity_item.text.eex:12
|
||||
|
@ -482,68 +483,64 @@ msgstr "Un perfil anónimo"
|
|||
|
||||
#: lib/web/templates/email/email_anonymous_activity.html.heex:107
|
||||
#: lib/web/templates/email/email_anonymous_activity.text.eex:14
|
||||
#, elixir-autogen, elixir-format
|
||||
#, elixir-autogen, elixir-format, fuzzy
|
||||
msgid "%{profile} has posted a private announcement about event %{event}."
|
||||
msgstr "%{profile} publicó un anuncio privado sobre el evento %{event}."
|
||||
msgstr "%{profile} publicó un anuncio en el evento %{event}."
|
||||
|
||||
#: lib/web/templates/email/email_anonymous_activity.html.heex:50
|
||||
#: lib/web/templates/email/email_anonymous_activity.text.eex:6
|
||||
#, elixir-autogen, elixir-format
|
||||
#, elixir-autogen, elixir-format, fuzzy
|
||||
msgid "%{profile} has posted a public announcement under event %{event}."
|
||||
msgstr "%{profile} publicó un anuncio privado en el evento %{event}."
|
||||
msgstr "%{profile} publicó un anuncio en el evento %{event}."
|
||||
|
||||
#: lib/web/templates/email/activity/_conversation_activity_item.html.heex:3
|
||||
#, elixir-autogen, elixir-format
|
||||
#, elixir-autogen, elixir-format, fuzzy
|
||||
msgid "%{profile} mentionned you in a %{conversation}."
|
||||
msgstr "%{profile} te mencionó en una %{conversation}."
|
||||
msgstr "%{profile} te mencionó en un comentario en el evento %{event}."
|
||||
|
||||
#: lib/web/templates/email/activity/_conversation_activity_item.text.eex:1
|
||||
#, elixir-autogen, elixir-format
|
||||
#, elixir-autogen, elixir-format, fuzzy
|
||||
msgid "%{profile} mentionned you in a conversation."
|
||||
msgstr "%{profile} te mencionó en una conversación."
|
||||
msgstr "%{profile} te mencionó en un comentario en el evento %{event}."
|
||||
|
||||
#: lib/service/activity/renderer/conversation.ex:36
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "%{profile} replied to your message"
|
||||
msgstr "%{profile} respondió a tu mensaje"
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/templates/email/activity/_conversation_activity_item.html.heex:10
|
||||
#, elixir-autogen, elixir-format
|
||||
#, elixir-autogen, elixir-format, fuzzy
|
||||
msgid "%{profile} replied you in a %{conversation}."
|
||||
msgstr "%{profile} te respondió en una %{conversation}."
|
||||
msgstr "%{profile} respondió a la discusión %{discussion}."
|
||||
|
||||
#: lib/web/templates/email/activity/_conversation_activity_item.text.eex:6
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "%{profile} replied you in a conversation."
|
||||
msgstr "%{profile} te respondió en una conversación."
|
||||
msgstr ""
|
||||
|
||||
#: lib/service/activity/renderer/conversation.ex:49
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "%{profile} sent a private message about event %{event}"
|
||||
msgstr "%{profile} envió un mensaje privado sobre el evento %{event}"
|
||||
msgstr ""
|
||||
|
||||
#: lib/service/activity/renderer/conversation.ex:23
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "%{profile} sent you a message"
|
||||
msgstr "%{profile} te envió un mensaje"
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/email/activity.ex:52
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Informations about your event %{event}"
|
||||
msgstr "Información sobre el evento %{event}"
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/templates/email/email_anonymous_activity.html.heex:118
|
||||
#: lib/web/templates/email/email_anonymous_activity.text.eex:20
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "It might give details on how to join the event, so make sure to read it appropriately."
|
||||
msgstr ""
|
||||
"Puede contener detalles de como llegar al evento, asegurate de leerlo con "
|
||||
"atención."
|
||||
|
||||
#: lib/web/templates/email/email_anonymous_activity.html.heex:156
|
||||
#: lib/web/templates/email/email_anonymous_activity.text.eex:28
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "This information is sent privately to you as a person who registered for this event. Share the informations above with other people with caution."
|
||||
msgstr ""
|
||||
"Esta información le fue enviada de manera privada porque se registró al "
|
||||
"evento. Comparta la información anterior con otras personas con precaución."
|
||||
|
|
|
@ -3,16 +3,17 @@ msgstr ""
|
|||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-09-24 14:39+0000\n"
|
||||
"PO-Revision-Date: 2024-04-18 09:03+0000\n"
|
||||
"Last-Translator: GSalinas <gsalinastellez@gmail.com>\n"
|
||||
"PO-Revision-Date: 2023-10-22 18:27+0000\n"
|
||||
"Last-Translator: Jaime Marquínez Ferrándiz <jaime.marquinez."
|
||||
"ferrandiz@fastmail.net>\n"
|
||||
"Language-Team: Spanish <https://weblate.framasoft.org/projects/mobilizon/"
|
||||
"backend/es/>\n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\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.4.3\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.0.1\n"
|
||||
|
||||
#: lib/web/templates/email/password_reset.html.heex:66
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -2314,7 +2315,7 @@ msgstr "¡Hasta la próxima vez!"
|
|||
|
||||
#: lib/web/templates/email/group_suspension.html.heex:67
|
||||
#: lib/web/templates/email/group_suspension.text.eex:5
|
||||
#, elixir-autogen, elixir-format
|
||||
#, elixir-autogen, elixir-format, fuzzy
|
||||
msgid "As this group was located on this instance, all of its data has been irretrievably deleted."
|
||||
msgstr ""
|
||||
"Como este grupo estaba ubicado en esta instancia, todos sus datos se han "
|
||||
|
@ -2333,49 +2334,49 @@ msgstr "Eventos marcados"
|
|||
#: lib/service/export/participants/common.ex:65
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Participant registration date"
|
||||
msgstr "Fecha de inscripción del participante"
|
||||
msgstr "Fecha de registro del participante"
|
||||
|
||||
#: lib/web/templates/email/anonymous_participation_confirmation.html.heex:113
|
||||
#: lib/web/templates/email/event_participation_confirmed.html.heex:122
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Cancel my attendance"
|
||||
msgstr "Cancelar mi participación"
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/templates/email/anonymous_participation_confirmation.html.heex:90
|
||||
#: lib/web/templates/email/event_participation_confirmed.html.heex:99
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "If you wish to cancel your participation, simply click on the link below."
|
||||
msgstr "Si desea cancelar su participación, haga click en el enlace abajo."
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/email/admin.ex:142
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Email configuration test for %{instance}"
|
||||
msgstr "Test de configuración de correo electrónico para %{instance}"
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/templates/email/email_configuration_test.html.heex:47
|
||||
#: lib/web/templates/email/email_configuration_test.text.eex:3
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "If you received this email, the email configuration seems to be correct."
|
||||
msgstr ""
|
||||
"Si recibió este correo electrónico, la configuración del correo electrónico "
|
||||
"parece correcta."
|
||||
|
||||
#: lib/web/templates/email/email_configuration_test.html.heex:18
|
||||
#: lib/web/templates/email/email_configuration_test.text.eex:1
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Well done!"
|
||||
msgstr "Bien hecho!"
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/templates/api/terms.html.heex:55
|
||||
#, elixir-autogen, elixir-format
|
||||
#, 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 ""
|
||||
"Cuando decimos \"nosotros\", \"nuestro\" o \"nosotros\" en este documento, "
|
||||
"nos referimos a los propietarios, operadores y administradores de esta "
|
||||
"instancia de Mobilizon. El software de Mobilizon es proporcionado por el "
|
||||
"equipo de colaboradores de Mobilizon. A menos que se indique explícitamente, "
|
||||
"esta instancia de Mobilizon es un servicio independiente que utiliza el "
|
||||
"código fuente de Mobilizon. Puede encontrar más información sobre esta "
|
||||
"instancia en la página <a href=\"/about/instance\"> \"Acerca de esta "
|
||||
"equipo de contribuyentes de Mobilizon, respaldado por <a href=\"https://"
|
||||
"framasoft.org\"> Framasoft </a>, una organización educativa popular francesa "
|
||||
"sin fines de lucro que aboga por el Software Libre. A menos que se indique "
|
||||
"explícitamente, esta instancia de Mobilizon es un servicio independiente que "
|
||||
"utiliza el código fuente de Mobilizon. Puede encontrar más información sobre "
|
||||
"esta instancia en la página <a href=\"/about/instance\"> \"Acerca de esta "
|
||||
"instancia\" </a>."
|
||||
|
|
|
@ -8,15 +8,15 @@
|
|||
## to merge POT files into PO files.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2024-04-18 09:03+0000\n"
|
||||
"Last-Translator: GSalinas <gsalinastellez@gmail.com>\n"
|
||||
"PO-Revision-Date: 2022-11-01 21:38+0000\n"
|
||||
"Last-Translator: Berto Te <ateira@3fpj.com>\n"
|
||||
"Language-Team: Spanish <https://weblate.framasoft.org/projects/mobilizon/"
|
||||
"backend-errors/es/>\n"
|
||||
"Language: es\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.4.3\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 4.14.1\n"
|
||||
|
||||
#: lib/mobilizon/discussions/discussion.ex:68
|
||||
#, elixir-autogen
|
||||
|
@ -1193,9 +1193,9 @@ msgid "Application token not found"
|
|||
msgstr "Token de aplicación no encontrado"
|
||||
|
||||
#: lib/graphql/resolvers/application.ex:90
|
||||
#, elixir-autogen, elixir-format
|
||||
#, elixir-autogen, elixir-format, fuzzy
|
||||
msgid "Error while revoking token"
|
||||
msgstr "Error al revocar el token"
|
||||
msgstr "Error al guardar el informe"
|
||||
|
||||
#: lib/web/controllers/application_controller.ex:61
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -1263,81 +1263,71 @@ msgstr "El client_id provisto o el device_code asociado es inválido"
|
|||
#, elixir-autogen, elixir-format
|
||||
msgid "The device user code was not provided before approving the application"
|
||||
msgstr ""
|
||||
"El código de usuario del dispositivo no se proporcionó antes de la "
|
||||
"aprobación de la aplicación"
|
||||
|
||||
#: lib/web/controllers/application_controller.ex:301
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "The given device_code has expired"
|
||||
msgstr "El device_code provisto ha caducado"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/application.ex:45
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "The given redirect_uri is not in the list of allowed redirect URIs"
|
||||
msgstr ""
|
||||
"La redirect_uri dada no se encuentra en la lista de URI's de redirección "
|
||||
"permitidas"
|
||||
|
||||
#: lib/web/controllers/application_controller.ex:155
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "The given scope is not in the list of the app declared scopes"
|
||||
msgstr ""
|
||||
"El objetivo provisto no se encuentra en la lista de objetivos declarados de "
|
||||
"la applicación"
|
||||
|
||||
#: lib/graphql/resolvers/application.ex:112
|
||||
#: lib/graphql/resolvers/application.ex:154
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "The given user code has expired"
|
||||
msgstr "El codigo de usuario provisto ha caducado"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/application.ex:118
|
||||
#: lib/graphql/resolvers/application.ex:146
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "The given user code is invalid"
|
||||
msgstr "Elcodigo de usuario provisto es invalido"
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/controllers/application_controller.ex:408
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "The provided client_id does not match the provided code"
|
||||
msgstr "El client_id provisto no corresponde con el código provisto"
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/controllers/application_controller.ex:411
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "The provided client_secret is invalid"
|
||||
msgstr "El client_secret provisto es inválido"
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/controllers/application_controller.ex:404
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "The provided code is invalid or expired"
|
||||
msgstr "El código provisto es inválido o ha caducado"
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/controllers/application_controller.ex:415
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "The provided scope is invalid or not included in the app declared scopes"
|
||||
msgstr ""
|
||||
"El objetivo provisto es inválido o no se encuentra en la lista de objetivos "
|
||||
"declarados de la applicación"
|
||||
|
||||
#: lib/web/controllers/application_controller.ex:47
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "The scope parameter is not a space separated list of valid scopes"
|
||||
msgstr ""
|
||||
"La variable de objetivos no es una lista separada por espacios de objetivos "
|
||||
"validos"
|
||||
|
||||
#: lib/web/controllers/application_controller.ex:289
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "The user rejected the requested authorization"
|
||||
msgstr "El usuario rechazó la autorización solicitada"
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/controllers/application_controller.ex:401
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "This redirect URI is not allowed"
|
||||
msgstr "Esta URI de redirección no está autorizada"
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/controllers/application_controller.ex:378
|
||||
#, elixir-autogen, elixir-format
|
||||
#, elixir-autogen, elixir-format, fuzzy
|
||||
msgid "Token not found"
|
||||
msgstr "Token no encontrado"
|
||||
|
||||
|
@ -1349,103 +1339,91 @@ msgstr "Demasiadas peticiones"
|
|||
#: lib/web/controllers/application_controller.ex:181
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Unable to produce device code"
|
||||
msgstr "No se puedo generar el código de dispositivo"
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/controllers/application_controller.ex:370
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Unable to revoke token"
|
||||
msgstr "No se puede revocar el token"
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/controllers/application_controller.ex:195
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "You need to pass both client_id and scope as parameters to obtain a device code"
|
||||
msgstr ""
|
||||
"Para obtener un código de dispositivo, es necesario pasar como parámetros el "
|
||||
"client_id y el objetivo"
|
||||
|
||||
#: lib/web/controllers/application_controller.ex:133
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "You need to provide a valid redirect_uri to autorize an application"
|
||||
msgstr "Debe proporcionar una redirect_uri válida para autorizar una aplicación"
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/controllers/application_controller.ex:123
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "You need to specify client_id, redirect_uri, scope and state to autorize an application"
|
||||
msgstr ""
|
||||
"Debe especificar client_id, redirect_uri, scope y state para autorizar una "
|
||||
"aplicación"
|
||||
|
||||
#: lib/graphql/resolvers/user.ex:306
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Couldn't send an email. Internal error."
|
||||
msgstr "No se ha podido enviar un correo electrónico. Error interno."
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/participant.ex:293
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Participation is already confirmed"
|
||||
msgstr "La participación ya está confirmada"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/participant.ex:290
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Participation is confirmed but not approved yet by an organizer"
|
||||
msgstr ""
|
||||
"La participación esta confirmada pero aún no esta aprobada por un organizador"
|
||||
|
||||
#: lib/graphql/resolvers/event.ex:287
|
||||
#: lib/graphql/resolvers/event.ex:376
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Providing external registration is not allowed"
|
||||
msgstr "No se permite el registro externo"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/push_subscription.ex:48
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "The same push subscription has already been registered"
|
||||
msgstr "Ya se ha registrado el mismo pedidio de suscripción"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/admin.ex:554
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "This instance is pending follow approval"
|
||||
msgstr "La instancia está pendiente de aprobación"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/schema/custom/timezone.ex:25
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Timezone ID %{timezone} is invalid"
|
||||
msgstr "El ID de zona horaria %{timezone} no es válido."
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/admin.ex:557
|
||||
#, elixir-autogen, elixir-format
|
||||
#, elixir-autogen, elixir-format, fuzzy
|
||||
msgid "You are already following this instance"
|
||||
msgstr "Ya estas siguiendo este grupo"
|
||||
|
||||
#: lib/graphql/resolvers/user.ex:310
|
||||
#, elixir-autogen, elixir-format
|
||||
#, elixir-autogen, elixir-format, fuzzy
|
||||
msgid "You requested again a confirmation email too soon. Please try again in a few minutes"
|
||||
msgstr ""
|
||||
"Ha solicitado un correo electrónico de confirmación demasiado rápido. Por "
|
||||
"favor, inténtelo de nuevo en unos minutos"
|
||||
"Solicitó de nuevo un correo electrónico de confirmación demasiado pronto"
|
||||
|
||||
#: lib/graphql/resolvers/user.ex:341
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "You requested again a password reset email too soon. Please try again in a few minutes"
|
||||
msgstr ""
|
||||
"Ha solicitado un correo electrónico de restablecimiento de contraseña "
|
||||
"demasiado pronto. Por favor, inténtelo de nuevo en unos minutos"
|
||||
|
||||
#: lib/graphql/resolvers/user.ex:368
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "The token you provided is invalid. Make sure that the URL is exactly the one provided inside the email you got."
|
||||
msgstr ""
|
||||
"El token proporcionado no es válido. Asegúrate de que la URL es exactamente "
|
||||
"la misma que la proporcionada en el correo electrónico que recibiste."
|
||||
|
||||
#: lib/graphql/resolvers/conversation.ex:164
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Conversation needs to mention at least one participant that's not yourself"
|
||||
msgstr ""
|
||||
"La conversación tiene que mencionar al menos un participante que no seas tú "
|
||||
"mismo"
|
||||
|
||||
#: lib/graphql/resolvers/participant.ex:401
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "There are no participants matching the audience you've selected."
|
||||
msgstr "No hay participantes que coincidan con el público que has seleccionado."
|
||||
msgstr ""
|
||||
|
|
|
@ -3,7 +3,7 @@ msgstr ""
|
|||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-11-25 07:55+0000\n"
|
||||
"PO-Revision-Date: 2024-03-08 15:25+0000\n"
|
||||
"PO-Revision-Date: 2023-12-04 18:10+0000\n"
|
||||
"Last-Translator: Milo Ivir <mail@milotype.de>\n"
|
||||
"Language-Team: Croatian <https://weblate.framasoft.org/projects/mobilizon/"
|
||||
"activity/hr/>\n"
|
||||
|
@ -13,7 +13,7 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 5.4.2\n"
|
||||
"X-Generator: Weblate 5.2.1\n"
|
||||
|
||||
## This file is a PO Template file.
|
||||
##
|
||||
|
@ -58,13 +58,13 @@ msgstr "%{profile} su dodali %{member}."
|
|||
#: lib/web/templates/email/activity/_discussion_activity_item.text.eex:19
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "%{profile} archived the discussion %{discussion}."
|
||||
msgstr "%{profile} je arhivirao/la raspravu %{discussion}."
|
||||
msgstr "%{profile} su arhivirali razgovor %{discussion}."
|
||||
|
||||
#: lib/web/templates/email/activity/_discussion_activity_item.html.heex:3
|
||||
#: lib/web/templates/email/activity/_discussion_activity_item.text.eex:1
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "%{profile} created the discussion %{discussion}."
|
||||
msgstr "%{profile} je stvorio/la raspravu %{discussion}."
|
||||
msgstr "%{profile} su stvorili razgovor %{discussion}."
|
||||
|
||||
#: lib/web/templates/email/activity/_resource_activity_item.html.heex:4
|
||||
#: lib/web/templates/email/activity/_resource_activity_item.text.eex:2
|
||||
|
@ -88,7 +88,7 @@ msgstr "%{profile} su stvorili resurs %{resource}."
|
|||
#: lib/web/templates/email/activity/_discussion_activity_item.text.eex:25
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "%{profile} deleted the discussion %{discussion}."
|
||||
msgstr "%{profile} je izbrisao/la raspravu %{discussion}."
|
||||
msgstr "%{profile} su izbrisali razgovor %{discussion}."
|
||||
|
||||
#: lib/web/templates/email/activity/_resource_activity_item.html.heex:76
|
||||
#: lib/web/templates/email/activity/_resource_activity_item.text.eex:40
|
||||
|
@ -130,7 +130,7 @@ msgstr "%{profile} su izašli iz grupe."
|
|||
#: lib/web/templates/email/activity/_discussion_activity_item.text.eex:13
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "%{profile} renamed the discussion %{discussion}."
|
||||
msgstr "%{profile} je preimenovao/la raspravu %{discussion}."
|
||||
msgstr "%{profile} su preimenovali razgovor %{discussion}."
|
||||
|
||||
#: lib/web/templates/email/activity/_resource_activity_item.html.heex:24
|
||||
#: lib/web/templates/email/activity/_resource_activity_item.text.eex:14
|
||||
|
@ -149,7 +149,7 @@ msgstr ""
|
|||
#: lib/web/templates/email/activity/_discussion_activity_item.text.eex:7
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "%{profile} replied to the discussion %{discussion}."
|
||||
msgstr "%{profile} je odgovorio/la na raspravu %{discussion}."
|
||||
msgstr "%{profile} su odgovorili na razgovor %{discussion}."
|
||||
|
||||
#: lib/web/templates/email/activity/_group_activity_item.html.heex:12
|
||||
#: lib/web/templates/email/activity/_group_activity_item.text.eex:7
|
||||
|
@ -448,32 +448,32 @@ msgstr "%{profile} su stvorili resurs %{resource} u grupi %{group}."
|
|||
#: lib/service/activity/renderer/discussion.ex:85
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "%{profile} archived the discussion %{discussion} in group %{group}."
|
||||
msgstr "%{profile} je arhivirao/la raspravu %{discussion} u grupi %{group}."
|
||||
msgstr "%{profile} su arhivirali razgovor %{discussion} u grupi %{group}."
|
||||
|
||||
#: lib/service/activity/renderer/discussion.ex:25
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "%{profile} created the discussion %{discussion} in group %{group}."
|
||||
msgstr "%{profile} je stvorio/la raspravu %{discussion} u grupi %{group}."
|
||||
msgstr "%{profile} su stvorili razgovor %{discussion} u grupi %{group}."
|
||||
|
||||
#: lib/service/activity/renderer/discussion.ex:100
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "%{profile} deleted the discussion %{discussion} in group %{group}."
|
||||
msgstr "%{profile} je izbrisao/la raspravu %{discussion} u grupi %{group}."
|
||||
msgstr "%{profile} su izbrisali razgovor %{discussion} u grupi %{group}."
|
||||
|
||||
#: lib/service/activity/renderer/discussion.ex:55
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "%{profile} mentionned you in the discussion %{discussion} in group %{group}."
|
||||
msgstr "%{profile} te je spomenuo/la u raspravi %{discussion} u grupi %{group}."
|
||||
msgstr "%{profile} su vas spomenuli u razgovoru %{discussion} u grupi %{group}."
|
||||
|
||||
#: lib/service/activity/renderer/discussion.ex:70
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "%{profile} renamed the discussion %{discussion} in group %{group}."
|
||||
msgstr "%{profile} je preimenovao/la raspravu %{discussion} u grupi %{group}."
|
||||
msgstr "%{profile} su preimenovali razgovor %{discussion} u grupi %{group}."
|
||||
|
||||
#: lib/service/activity/renderer/discussion.ex:40
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "%{profile} replied to the discussion %{discussion} in group %{group}."
|
||||
msgstr "%{profile} je odgovorio/la na raspravu %{discussion} u grupi %{group}."
|
||||
msgstr "%{profile} su odgovorili na razgovor %{discussion} u grupi %{group}."
|
||||
|
||||
#: lib/web/templates/email/activity/_member_activity_item.html.heex:36
|
||||
#: lib/web/templates/email/activity/_member_activity_item.text.eex:33
|
||||
|
|
|
@ -3,7 +3,7 @@ msgstr ""
|
|||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-11-25 07:56+0000\n"
|
||||
"PO-Revision-Date: 2024-04-25 13:45+0000\n"
|
||||
"PO-Revision-Date: 2023-12-21 20:11+0000\n"
|
||||
"Last-Translator: Milo Ivir <mail@milotype.de>\n"
|
||||
"Language-Team: Croatian <https://weblate.framasoft.org/projects/mobilizon/"
|
||||
"backend/hr/>\n"
|
||||
|
@ -11,9 +11,9 @@ msgstr ""
|
|||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
"X-Generator: Weblate 5.5\n"
|
||||
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 5.3.1\n"
|
||||
|
||||
#: lib/web/templates/email/password_reset.html.heex:66
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -227,8 +227,8 @@ msgstr "Tokeni za tvoju identifikaciju"
|
|||
msgctxt "terms"
|
||||
msgid "We also may retain server logs which include the IP address of every request to our server."
|
||||
msgstr ""
|
||||
"Također možemo zadržati zapisnike servera koji uključuju IP adresu svakog "
|
||||
"poslanog upita na naš server."
|
||||
"Također možemo zadržati zapisnike poslužitelja koji uključuju IP adresu "
|
||||
"svakog poslanog zahtjeva na naš poslužitelj."
|
||||
|
||||
#: lib/web/templates/api/privacy.html.heex:102
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -271,23 +271,12 @@ msgstr "Promjene u našim pravilima privatnosti"
|
|||
msgctxt "terms"
|
||||
msgid "If this server is in the EU or the EEA: Our site, products and services are all directed to people who are at least 16 years old. If you are under the age of 16, per the requirements of the GDPR (<a href=\"https://en.wikipedia.org/wiki/General_Data_Protection_Regulation\">General Data Protection Regulation</a>) do not use this site."
|
||||
msgstr ""
|
||||
"Ako se ovaj server nalazi u EU ili u Europskom gospodarskom prostoru (EEA): "
|
||||
"Naša stranica, proizvodi i usluge su namijenjene za osobe koje su starije od "
|
||||
"16 godina. Ako si mlađi od 16 godina, na osnovi uredbe GDPR (<a href=\"https"
|
||||
"://hr.wikipedia.org/wiki/Op%C4%87a_uredba_o_za%C5%A1titi_podataka\">Opća "
|
||||
"uredba o zaštiti podataka</a>) nemoj koristiti ovu stranicu."
|
||||
|
||||
#: lib/web/templates/api/privacy.html.heex:146
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "terms"
|
||||
msgid "If this server is in the USA: Our site, products and services are all directed to people who are at least 13 years old. If you are under the age of 13, per the requirements of COPPA (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>) do not use this site."
|
||||
msgstr ""
|
||||
"Ako se ovaj server nalazi u SAD-u: Naša stranica, proizvodi i usluge su "
|
||||
"namijenjene za osobe koje su starije od 13 godina. Ako si mlađi od 13 "
|
||||
"godina, na osnovi zakona COPPA (<a href=\"https://en.wikipedia.org/wiki/"
|
||||
"Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy "
|
||||
"Protection Act</a>) (Zakon o zaštiti privatnosti djece na internetu) nemoj "
|
||||
"koristiti ovu stranicu."
|
||||
|
||||
#: lib/web/templates/api/privacy.html.heex:160
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -302,8 +291,6 @@ msgstr ""
|
|||
msgctxt "terms"
|
||||
msgid "Law requirements can be different if this server is in another jurisdiction."
|
||||
msgstr ""
|
||||
"Zakonske regulative se mogu razlikovati ako se ovaj server nalazi u jednoj "
|
||||
"drugoj jurisdikciji."
|
||||
|
||||
#: lib/web/templates/api/privacy.html.heex:137
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -316,30 +303,18 @@ msgstr "Korištenje stranice od djece"
|
|||
msgctxt "terms"
|
||||
msgid "The email address you provide may be used to send you information, updates and notifications about other people\n interacting with your content or sending you messages and to respond to inquiries, and/or other requests or\n questions."
|
||||
msgstr ""
|
||||
"E-mail adresa koju navedeš može se koristiti za slanje informacija, "
|
||||
"aktualiziranja i obavijesti o drugim osobama\n"
|
||||
" koji interagiraju s tvojim sadržajem ili ti šalju poruke te za "
|
||||
"odgovaranje na upite i/ili druge zahtjeve ili\n"
|
||||
" pitanja."
|
||||
|
||||
#: lib/web/templates/api/privacy.html.heex:61
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "terms"
|
||||
msgid "To aid moderation of the community, for example comparing your IP address with other known ones to determine ban\n evasion or other violations."
|
||||
msgstr ""
|
||||
"Pomoći pri moderiranju zajednice, na primjer usporedbom tvoje IP adrese s "
|
||||
"drugim poznatim adresama za utvrđivanja zabrane\n"
|
||||
" ili drugih povreda."
|
||||
|
||||
#: lib/web/templates/api/privacy.html.heex:54
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "terms"
|
||||
msgid "To provide the core functionality of Mobilizon. Depending on this instance's policy you may only be able to\n interact with other people's content and post your own content if you are logged in."
|
||||
msgstr ""
|
||||
"Pružiti temeljnu funkcionalnost Mobilizona. Ovisno o politici ove instance, "
|
||||
"možda ćete moći samo\n"
|
||||
" komunicirati sa sadržajem drugih ljudi i objavljivati vlastiti sadržaj "
|
||||
"ako ste prijavljeni."
|
||||
|
||||
#: lib/web/templates/api/privacy.html.heex:10
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -581,7 +556,7 @@ msgstr ""
|
|||
#, elixir-autogen, elixir-format
|
||||
msgctxt "terms"
|
||||
msgid "Your Content & Conduct"
|
||||
msgstr "Tvoj sadržaj i ponašanje"
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/templates/api/terms.html.heex:263
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -600,8 +575,6 @@ msgstr ""
|
|||
msgctxt "terms"
|
||||
msgid "For full details about the Mobilizon software <a href=\"https://joinmobilizon.org\">see here</a>."
|
||||
msgstr ""
|
||||
"Pogledaj sve detalje o Mobilizon softveru <a href=\"https://joinmobilizon."
|
||||
"org\">ovdje</a>."
|
||||
|
||||
#: lib/web/templates/api/terms.html.heex:47
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -660,10 +633,6 @@ msgstr ""
|
|||
msgctxt "terms"
|
||||
msgid "You can remove the content that you posted by deleting it. Once you delete your content, it will not appear on the Service, but copies of your deleted content may remain in our system or backups for some period of time. Web server access logs might also be stored for some time in the system."
|
||||
msgstr ""
|
||||
"Sadržaj koji si objavio možeš ukloniti brisanjem. Nakon što izbrišeš svoj "
|
||||
"sadržaj, on se neće pojaviti na usluzi, ali kopije tvog izbrisanog sadržaja "
|
||||
"mogu ostati u našem sustavu ili sigurnosnim kopijama neko vrijeme. Zapisnici "
|
||||
"pristupa web serveru se također mogu neko vrijeme zadržati u sustavu."
|
||||
|
||||
#: lib/web/templates/api/terms.html.heex:306
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -917,9 +886,6 @@ msgstr ""
|
|||
#, elixir-autogen, elixir-format
|
||||
msgid "If you did not trigger this change yourself, it is likely that someone has gained access to your %{host} account. Please log in and change your password immediately. If you cannot login, contact the admin on %{host}."
|
||||
msgstr ""
|
||||
"Ako ovu promjenu nisi ti pokrenuo/la, vjerojatno je netko dobio pristup tvom "
|
||||
"%{host} računu. Prijavi se i odmah promijeni lozinku. Ako se ne možeš "
|
||||
"prijaviti, kontaktiraj administratora na %{host}."
|
||||
|
||||
#: lib/web/templates/email/password_reset.text.eex:12
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -1194,7 +1160,7 @@ msgstr ""
|
|||
#, elixir-autogen, elixir-format
|
||||
msgctxt "terms"
|
||||
msgid "If you delete this information, you need to login again."
|
||||
msgstr "Ako izbrišeš ove podatke morat ćeš se ponovo prijaviti."
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/templates/api/privacy.html.heex:111
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -1212,15 +1178,13 @@ msgstr ""
|
|||
#, elixir-autogen, elixir-format
|
||||
msgctxt "terms"
|
||||
msgid "Our responsibility"
|
||||
msgstr "Naša odgovornost"
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/templates/api/privacy.html.heex:87
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "terms"
|
||||
msgid "Retain server logs containing the IP address of all requests to this server, insofar as such logs are kept, no more than 90 days."
|
||||
msgstr ""
|
||||
"Zapisnici servera koji sadrže IP adrese svih upita prema ovom serveru brišu "
|
||||
"se nakon 90 dana, pod uvjetom da se takvi zapisnici vode."
|
||||
|
||||
#: lib/web/templates/api/privacy.html.heex:3
|
||||
#: lib/web/templates/api/terms.html.heex:39
|
||||
|
@ -1228,7 +1192,7 @@ msgstr ""
|
|||
msgctxt "terms"
|
||||
msgid "Some terms, technical or otherwise, used in the text below may cover concepts that are difficult to grasp. We have provided <a href=\"/glossary\">a glossary</a> to help you understand them better."
|
||||
msgstr ""
|
||||
"Neki tehnički ili drugi izrazi koji se koriste u daljnjem tekstu mogu "
|
||||
"Neki tehnički ili drugi izrazi koji se koriste u donjem tekstu mogu "
|
||||
"pokrivati pojmove koji se teško razumiju. Za lakše razumijevanje pojmova "
|
||||
"postoji <a href=\"/glossary\">glosar</a>."
|
||||
|
||||
|
@ -1441,13 +1405,15 @@ msgstr "Feed za %{email} na %{instance}"
|
|||
#, elixir-autogen, elixir-format
|
||||
msgid "If the issue persists, you may contact the server administrator at %{contact}."
|
||||
msgstr ""
|
||||
"Ako se problem nastavi pojavljivati obratiti se administratoru servera na "
|
||||
"%{contact}."
|
||||
"Ako se problem nastavi pojavljivati, možeš se obratiti administratoru "
|
||||
"poslužitelja na %{contact}."
|
||||
|
||||
#: lib/web/templates/error/500_page.html.heex:59
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "If the issue persists, you may try to contact the server administrator."
|
||||
msgstr "Ako se problem nastavi pojavljivati obratiti se administratoru servera."
|
||||
msgstr ""
|
||||
"Ako se problem nastavi pojavljivati, možeš se pokušati obratiti "
|
||||
"administratoru poslužitelja."
|
||||
|
||||
#: lib/web/templates/error/500_page.html.heex:82
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -1457,7 +1423,7 @@ msgstr "Tehnički detalji"
|
|||
#: lib/web/templates/error/500_page.html.heex:52
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "The Mobilizon server %{instance} seems to be temporarily down."
|
||||
msgstr "Čini se da Mobilizon server %{instance} privremeno nije dostupan."
|
||||
msgstr "Čini se da Mobilizon poslužitej %{instance} privremeno nije dostupan."
|
||||
|
||||
#: lib/service/export/feed.ex:72
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -1482,7 +1448,7 @@ msgstr ""
|
|||
#, elixir-autogen, elixir-format
|
||||
msgid "Your instance's moderation team has decided to suspend <b>%{group_name}</b> (%{group_address}). You are no longer a member of this group."
|
||||
msgstr ""
|
||||
"Tim za moderiranje tvoje instance je odlučio suspendirati grupu "
|
||||
"Tim za moderiranje tvoje instance je odlučio suspendiratigrupu "
|
||||
"<b>%{group_name}</b> (%{group_address}). Više nisi član ove grupe."
|
||||
|
||||
#: lib/web/templates/email/actor_suspension_participants.html.heex:18
|
||||
|
@ -2192,13 +2158,7 @@ msgid "Well done!"
|
|||
msgstr ""
|
||||
|
||||
#: lib/web/templates/api/terms.html.heex:55
|
||||
#, elixir-autogen, elixir-format
|
||||
#, 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 ""
|
||||
"Kada u ovom dokumentu kažemo „mi”, „naš” ili „nas”, mislimo na vlasnike, "
|
||||
"operatere i administratore ove Mobilizon instance. Softver Mobilizon "
|
||||
"osigurava tim dopinositelja Mobilizona. Ukoliko nije izričito navedeno, ova "
|
||||
"je Mobilizon instanca neovisna usluga koja koristi Mobilizonov izvorni kod. "
|
||||
"Više informacija o ovoj instanci se mogu pronaći na stranici <a href=\"/"
|
||||
"about/instance\">„O ovoj instanci”</a>."
|
||||
|
|
|
@ -3,7 +3,7 @@ msgstr ""
|
|||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-11-25 07:56+0000\n"
|
||||
"PO-Revision-Date: 2024-04-25 13:45+0000\n"
|
||||
"PO-Revision-Date: 2023-12-04 18:30+0000\n"
|
||||
"Last-Translator: Milo Ivir <mail@milotype.de>\n"
|
||||
"Language-Team: Croatian <https://weblate.framasoft.org/projects/mobilizon/"
|
||||
"backend-errors/hr/>\n"
|
||||
|
@ -11,9 +11,9 @@ msgstr ""
|
|||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
"X-Generator: Weblate 5.5\n"
|
||||
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 5.2.1\n"
|
||||
|
||||
## This file is a PO Template file.
|
||||
##
|
||||
|
@ -393,7 +393,7 @@ msgstr "Komentar je već izbrisan"
|
|||
#: lib/graphql/resolvers/discussion.ex:69
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Discussion not found"
|
||||
msgstr "Rasprava nije pronađena"
|
||||
msgstr "Diskusija nije pronađena"
|
||||
|
||||
#: lib/graphql/resolvers/report.ex:71
|
||||
#: lib/graphql/resolvers/report.ex:90
|
||||
|
@ -434,7 +434,7 @@ msgstr "Interna greška"
|
|||
#: lib/graphql/resolvers/discussion.ex:222
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "No discussion with ID %{id}"
|
||||
msgstr "Ne postoji rasprava s ID oznakom %{id}"
|
||||
msgstr "Ne postoji diskusija s ID oznakom %{id}"
|
||||
|
||||
#: lib/graphql/resolvers/todos.ex:80
|
||||
#: lib/graphql/resolvers/todos.ex:107
|
||||
|
@ -627,7 +627,7 @@ msgstr ""
|
|||
#, elixir-autogen, elixir-format
|
||||
msgid "You can't set yourself to a lower member role for this group because you are the only administrator"
|
||||
msgstr ""
|
||||
"Ne možeš se postaviti na nižu ulogu člana za ovu grupu jer si ti jedini "
|
||||
"Ne možeš se postaviti na nižu ulogu člana za ovu grupu jer si jedini "
|
||||
"administrator"
|
||||
|
||||
#: lib/graphql/resolvers/comment.ex:149
|
||||
|
@ -653,7 +653,7 @@ msgstr "Nemaš dozvole za brisanje ovog tokena"
|
|||
#: 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 "Za prikaz zapisnika radnji moraš biti prijavljen/a i biti moderator"
|
||||
msgstr "Za prikaz zapisnike radnji moraš biti prijavljen/a i biti moderator"
|
||||
|
||||
#: lib/graphql/resolvers/report.ex:36
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -694,7 +694,7 @@ msgstr ""
|
|||
#: lib/graphql/resolvers/discussion.ex:84
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "You need to be logged-in to access discussions"
|
||||
msgstr "Za pristup raspravama moraš biti prijavljen/a"
|
||||
msgstr "Za pristup diskusijama moraš biti prijavljen/a"
|
||||
|
||||
#: lib/graphql/resolvers/resource.ex:98
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -769,7 +769,7 @@ msgstr "Za prikaz pregleda resursa moraš biti prijavljen/a"
|
|||
#: lib/graphql/resolvers/resource.ex:134
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Parent resource doesn't belong to this group"
|
||||
msgstr "Nadređeni resurs ne pripada ovoj grupi"
|
||||
msgstr ""
|
||||
|
||||
#: lib/mobilizon/users/user.ex:114
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -796,93 +796,93 @@ msgstr "Objava nije pronađena"
|
|||
#: lib/graphql/error.ex:100
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Invalid arguments passed"
|
||||
msgstr "Proslijeđeni su nevažeći argumenti"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/error.ex:106
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Invalid credentials"
|
||||
msgstr "Nevažeći podaci za prijavu"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/error.ex:104
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Reset your password to login"
|
||||
msgstr "Obnovi svoju lozinku za prijavu"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/error.ex:111
|
||||
#: lib/graphql/error.ex:116
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Resource not found"
|
||||
msgstr "Resurs nije pronađen"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/error.ex:123
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Something went wrong"
|
||||
msgstr "Dogodila se greška"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/error.ex:99
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Unknown Resource"
|
||||
msgstr "Nepoznat resurs"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/error.ex:109
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "You don't have permission to do this"
|
||||
msgstr "Za ovo nemaš dozvolu"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/error.ex:101
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "You need to be logged in"
|
||||
msgstr "Moraš biti prijavljen/a"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/member.ex:118
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "You can't accept this invitation with this profile."
|
||||
msgstr "Ovu pozivnicu ne možeš prihvatiti s ovim profilom."
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/member.ex:139
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "You can't reject this invitation with this profile."
|
||||
msgstr "Ovu pozivnicu ne možeš odbiti s ovim profilom."
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/media.ex:71
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "File doesn't have an allowed MIME type."
|
||||
msgstr "Datoteka nema dozvoljenu MIME vrstu."
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/group.ex:244
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Profile is not administrator for the group"
|
||||
msgstr "Profil nije administrator za grupu"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/event.ex:385
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "You can't edit this event."
|
||||
msgstr "Ovaj događaj ne možeš urediti."
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/event.ex:388
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "You can't attribute this event to this profile."
|
||||
msgstr "Ovaj događaj ne možeš pripisati ovom profilu."
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/member.ex:142
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "This invitation doesn't exist."
|
||||
msgstr "Ova pozivnica ne postoji."
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/member.ex:217
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "This member already has been rejected."
|
||||
msgstr "Ovaj je član već odbijen."
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/member.ex:241
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "You don't have the right to remove this member."
|
||||
msgstr "Nemaš prava za uklanjanje ovog člana."
|
||||
msgstr ""
|
||||
|
||||
#: lib/mobilizon/actors/actor.ex:385
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "This username is already taken."
|
||||
msgstr "Ovo je korisničko ime već zauzeto."
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/discussion.ex:81
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -953,7 +953,7 @@ msgstr ""
|
|||
#: lib/graphql/resolvers/discussion.ex:123
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Error while creating a discussion"
|
||||
msgstr "Greška tijekom stvaranje rasprave"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/user.ex:687
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -1074,17 +1074,17 @@ msgstr ""
|
|||
#: lib/graphql/resolvers/group.ex:382
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "You need to be logged-in to follow a group"
|
||||
msgstr "Za praćenje grupe moraš biti prijavljen/a"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/group.ex:431
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "You need to be logged-in to unfollow a group"
|
||||
msgstr "Za prekid praćenja grupe moraš biti prijavljen/a"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/group.ex:408
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "You need to be logged-in to update a group follow"
|
||||
msgstr "Za aktualiziranje praćenja grupe moraš biti prijavljen/a"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/member.ex:210
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -1099,7 +1099,7 @@ msgstr ""
|
|||
#: lib/graphql/resolvers/member.ex:252
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "You must be logged-in to remove a member"
|
||||
msgstr "Za uklanjanje člana moraš biti prijavljen/a"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/user.ex:174
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -1125,7 +1125,7 @@ msgstr "Nova uloga mora biti drugačija"
|
|||
#, elixir-autogen, elixir-format
|
||||
msgid "You need to be logged-in and an administrator to edit an user's details"
|
||||
msgstr ""
|
||||
"Za uređivanje podataka korisnika moraš biti prijavljen/a i biti administrator"
|
||||
"Za uređivanje podataka korisnika, moraš biti prijavljen(a) i administrator"
|
||||
|
||||
#: lib/graphql/api/groups.ex:33
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -1192,22 +1192,22 @@ msgstr ""
|
|||
#: lib/graphql/error.ex:118
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Application not found"
|
||||
msgstr "Aplikacija nije pronađena"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/error.ex:121
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Application token not found"
|
||||
msgstr "Token aplikacije nije pronađen"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/application.ex:90
|
||||
#, elixir-autogen, elixir-format
|
||||
#, elixir-autogen, elixir-format, fuzzy
|
||||
msgid "Error while revoking token"
|
||||
msgstr "Greška tijekom opoziva tokena"
|
||||
msgstr "Greška tijekom spremanja izvještaja"
|
||||
|
||||
#: lib/web/controllers/application_controller.ex:61
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Impossible to create application."
|
||||
msgstr "Aplikacija se ne može stvoriti."
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/controllers/application_controller.ex:353
|
||||
#, elixir-autogen, elixir-format
|
||||
|
|
|
@ -8,52 +8,45 @@
|
|||
## to merge POT files into PO files.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2024-05-14 22:26+0000\n"
|
||||
"Last-Translator: Coen Holten <coenholten@proton.me>\n"
|
||||
"Language-Team: Dutch <https://weblate.framasoft.org/projects/mobilizon/"
|
||||
"backend-errors/nl/>\n"
|
||||
"Language: nl\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.5.5\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
|
||||
#: lib/mobilizon/discussions/discussion.ex:68
|
||||
#, elixir-autogen
|
||||
msgid "can't be blank"
|
||||
msgstr "kan niet leeg zijn"
|
||||
msgstr ""
|
||||
|
||||
msgid "has already been taken"
|
||||
msgstr "is al bezet"
|
||||
msgstr ""
|
||||
|
||||
msgid "is invalid"
|
||||
msgstr "is ongeldig"
|
||||
msgstr ""
|
||||
|
||||
msgid "must be accepted"
|
||||
msgstr "moet worden geaccepteerd"
|
||||
msgstr ""
|
||||
|
||||
msgid "has invalid format"
|
||||
msgstr "heeft ongeldig formaat"
|
||||
msgstr ""
|
||||
|
||||
msgid "has an invalid entry"
|
||||
msgstr "heeft een ongeldige invoer"
|
||||
msgstr ""
|
||||
|
||||
msgid "is reserved"
|
||||
msgstr "is gereserveerd"
|
||||
msgstr ""
|
||||
|
||||
msgid "does not match confirmation"
|
||||
msgstr "komt niet overeen met bevestiging"
|
||||
msgstr ""
|
||||
|
||||
msgid "is still associated with this entry"
|
||||
msgstr "is nog steeds gekoppeld aan deze invoer"
|
||||
msgstr ""
|
||||
|
||||
msgid "are still associated with this entry"
|
||||
msgstr "zijn nog steeds verbonden met deze invoer"
|
||||
msgstr ""
|
||||
|
||||
msgid "should be %{count} character(s)"
|
||||
msgid_plural "should be %{count} character(s)"
|
||||
msgstr[0] "moet %{count} karakter zijn"
|
||||
msgstr[1] "moet %{count} karakter(s) zijn"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "should have %{count} item(s)"
|
||||
msgid_plural "should have %{count} item(s)"
|
||||
|
|
|
@ -3,17 +3,17 @@ msgstr ""
|
|||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-09-24 14:40+0000\n"
|
||||
"PO-Revision-Date: 2024-07-04 23:35+0000\n"
|
||||
"Last-Translator: ewm <gnu.ewm@protonmail.com>\n"
|
||||
"PO-Revision-Date: 2023-10-22 04:28+0000\n"
|
||||
"Last-Translator: Jakub Urbanowicz <tex@przeklad.pl>\n"
|
||||
"Language-Team: Polish <https://weblate.framasoft.org/projects/mobilizon/"
|
||||
"backend/pl/>\n"
|
||||
"Language: pl\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
|
||||
"|| n%100>=20) ? 1 : 2);\n"
|
||||
"X-Generator: Weblate 5.6.2\n"
|
||||
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
|
||||
"|| n%100>=20) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 5.0.1\n"
|
||||
|
||||
#: lib/web/templates/email/password_reset.html.heex:66
|
||||
#, elixir-autogen, elixir-format
|
||||
|
@ -2373,32 +2373,30 @@ msgstr "Data rejestracji uczestnika"
|
|||
#: lib/web/templates/email/event_participation_confirmed.html.heex:122
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Cancel my attendance"
|
||||
msgstr "Anuluj moją obecność"
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/templates/email/anonymous_participation_confirmation.html.heex:90
|
||||
#: lib/web/templates/email/event_participation_confirmed.html.heex:99
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "If you wish to cancel your participation, simply click on the link below."
|
||||
msgstr "Jeśli chcesz anulować swój udział, kliknij poniższy link."
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/email/admin.ex:142
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Email configuration test for %{instance}"
|
||||
msgstr "Test konfiguracji poczty e-mail dla %{instance}"
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/templates/email/email_configuration_test.html.heex:47
|
||||
#: lib/web/templates/email/email_configuration_test.text.eex:3
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "If you received this email, the email configuration seems to be correct."
|
||||
msgstr ""
|
||||
"Jeśli otrzymano tę wiadomość e-mail, konfiguracja poczty wydaje się być "
|
||||
"poprawna."
|
||||
|
||||
#: lib/web/templates/email/email_configuration_test.html.heex:18
|
||||
#: lib/web/templates/email/email_configuration_test.text.eex:1
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Well done!"
|
||||
msgstr "Dobra robota!"
|
||||
msgstr ""
|
||||
|
||||
#: lib/web/templates/api/terms.html.heex:55
|
||||
#, elixir-autogen, elixir-format, fuzzy
|
||||
|
|
|
@ -8,16 +8,16 @@
|
|||
## to merge POT files into PO files.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2024-07-04 23:35+0000\n"
|
||||
"Last-Translator: ewm <gnu.ewm@protonmail.com>\n"
|
||||
"PO-Revision-Date: 2023-10-22 23:11+0000\n"
|
||||
"Last-Translator: Jakub Urbanowicz <tex@przeklad.pl>\n"
|
||||
"Language-Team: Polish <https://weblate.framasoft.org/projects/mobilizon/"
|
||||
"backend-errors/pl/>\n"
|
||||
"Language: pl\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
|
||||
"|| n%100>=20) ? 1 : 2);\n"
|
||||
"X-Generator: Weblate 5.6.2\n"
|
||||
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
|
||||
"|| n%100>=20) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 5.0.1\n"
|
||||
|
||||
#: lib/mobilizon/discussions/discussion.ex:68
|
||||
#, elixir-autogen
|
||||
|
@ -1457,9 +1457,9 @@ msgstr ""
|
|||
#: lib/graphql/resolvers/conversation.ex:164
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Conversation needs to mention at least one participant that's not yourself"
|
||||
msgstr "Konwersacja musi zawierać co najmniej jedną wzmiankę o innym uczestniku"
|
||||
msgstr ""
|
||||
|
||||
#: lib/graphql/resolvers/participant.ex:401
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "There are no participants matching the audience you've selected."
|
||||
msgstr "Nie ma uczestników pasujących do wybranej grupy odbiorców."
|
||||
msgstr ""
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
defmodule Mobilizon.Storage.Repo.Migrations.CreateAdminSettingsMedias do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
create table(:admin_settings_medias) do
|
||||
add(:group, :string)
|
||||
add(:name, :string)
|
||||
add(:media_id, references(:medias, on_delete: :delete_all))
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
create(unique_index(:admin_settings_medias, [:group, :name]))
|
||||
end
|
||||
end
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |
BIN
public/img/pics/error.webp
Normal file
After Width: | Height: | Size: 112 KiB |
BIN
public/img/pics/event_creation-1024w.webp
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
public/img/pics/event_creation-480w.webp
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
public/img/pics/event_creation.webp
Normal file
After Width: | Height: | Size: 174 KiB |
BIN
public/img/pics/footer_1.webp
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
public/img/pics/footer_2.webp
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
public/img/pics/footer_3.webp
Normal file
After Width: | Height: | Size: 54 KiB |
BIN
public/img/pics/footer_4.webp
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
public/img/pics/footer_5.webp
Normal file
After Width: | Height: | Size: 76 KiB |
BIN
public/img/pics/group-1024w.webp
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
public/img/pics/group-480w.webp
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
public/img/pics/group.webp
Normal file
After Width: | Height: | Size: 193 KiB |
BIN
public/img/pics/homepage.webp
Normal file
After Width: | Height: | Size: 317 KiB |
BIN
public/img/pics/realisation.webp
Normal file
After Width: | Height: | Size: 222 KiB |
BIN
public/img/pics/rose.webp
Normal file
After Width: | Height: | Size: 21 KiB |
|
@ -169,18 +169,6 @@ type Config {
|
|||
"The instance's slogan"
|
||||
slogan: String
|
||||
|
||||
"The instance's logo"
|
||||
instanceLogo: Media
|
||||
|
||||
"The default picture"
|
||||
defaultPicture: Media
|
||||
|
||||
"The instance's primary color"
|
||||
primaryColor: String
|
||||
|
||||
"The instance's secondary color"
|
||||
secondaryColor: String
|
||||
|
||||
"The instance's contact details"
|
||||
contact: String
|
||||
|
||||
|
@ -199,9 +187,6 @@ type Config {
|
|||
"Whether the demo mode is enabled"
|
||||
demoMode: Boolean
|
||||
|
||||
"Whether the long events mode is enabled"
|
||||
longEvents: Boolean
|
||||
|
||||
"The country code from the IP"
|
||||
countryCode: String
|
||||
|
||||
|
@ -1893,15 +1878,6 @@ type RootMutationType {
|
|||
"The instance's contact details"
|
||||
contact: String
|
||||
|
||||
"The instance's logo"
|
||||
instanceLogo: MediaInput
|
||||
|
||||
"The instance's favicon"
|
||||
instanceFavicon: MediaInput
|
||||
|
||||
"The default picture"
|
||||
defaultPicture: MediaInput
|
||||
|
||||
"The instance's terms body text"
|
||||
instanceTerms: String
|
||||
|
||||
|
@ -2266,9 +2242,6 @@ type RootQueryType {
|
|||
|
||||
"Filter events by their end date"
|
||||
endsOn: DateTime
|
||||
|
||||
"Filter for long events in function of configuration parameter 'duration_of_long_event'"
|
||||
longevents: Boolean
|
||||
): Events
|
||||
|
||||
"Interact with an URI"
|
||||
|
@ -3725,15 +3698,6 @@ type AdminSettings {
|
|||
"The instance's contact details"
|
||||
contact: String
|
||||
|
||||
"The instance's logo"
|
||||
instanceLogo: Media
|
||||
|
||||
"The instance's favicon"
|
||||
instanceFavicon: Media
|
||||
|
||||
"The default picture"
|
||||
defaultPicture: Media
|
||||
|
||||
"The instance's terms body text"
|
||||
instanceTerms: String
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ body {
|
|||
@apply border-2 border-mbz-success bg-transparent text-mbz-success hover:bg-mbz-success hover:text-white;
|
||||
}
|
||||
.btn-outlined-warning {
|
||||
@apply border-2 bg-transparent dark:text-white hover:dark:text-slate-900 hover:bg-mbz-warning border-mbz-warning;
|
||||
@apply bg-transparent border dark:text-white hover:dark:text-slate-900 hover:bg-mbz-warning border-mbz-warning;
|
||||
}
|
||||
.btn-outlined-danger {
|
||||
@apply border-2 bg-transparent border-mbz-danger text-mbz-danger hover:bg-mbz-danger hover:text-white;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<o-taginput
|
||||
:modelValue="modelValueWithDisplayName"
|
||||
@update:modelValue="updateTags"
|
||||
@update:modelValue="(val: IActor[]) => $emit('update:modelValue', val)"
|
||||
:data="availableActors"
|
||||
:allow-autocomplete="true"
|
||||
:allow-new="false"
|
||||
|
@ -25,18 +25,14 @@ import { computed, ref } from "vue";
|
|||
import ActorInline from "./ActorInline.vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const emit = defineEmits<{
|
||||
"update:modelValue": [value: IActor[]];
|
||||
}>();
|
||||
|
||||
const updateTags = (val: IActor[]) => {
|
||||
emit("update:modelValue", val);
|
||||
};
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: IActor[];
|
||||
}>();
|
||||
|
||||
defineEmits<{
|
||||
"update:modelValue": [value: IActor[]];
|
||||
}>();
|
||||
|
||||
const modelValue = computed(() => props.modelValue);
|
||||
|
||||
const modelValueWithDisplayName = computed(() =>
|
||||
|
|
|
@ -2,6 +2,21 @@
|
|||
<div class="container mx-auto" id="error-wrapper">
|
||||
<div class="">
|
||||
<section>
|
||||
<div class="text-center">
|
||||
<picture>
|
||||
<source
|
||||
:srcset="`/img/pics/error-480w.webp 1x, /img/pics/error-1024w.webp 2x`"
|
||||
type="image/webp"
|
||||
/>
|
||||
<img
|
||||
:src="`/img/pics/error-480w.webp`"
|
||||
alt=""
|
||||
width="480"
|
||||
height="312"
|
||||
loading="lazy"
|
||||
/>
|
||||
</picture>
|
||||
</div>
|
||||
<o-notification variant="danger" class="">
|
||||
<h1>
|
||||
{{
|
||||
|
@ -93,7 +108,7 @@ import { IAnalyticsConfig, IConfig } from "@/types/config.model";
|
|||
import { computed, defineAsyncComponent, ref } from "vue";
|
||||
import { useQuery, useQueryLoading } from "@vue/apollo-composable";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useHead } from "@/utils/head";
|
||||
import { useHead } from "@unhead/vue";
|
||||
import { useAnalytics } from "@/composition/apollo/config";
|
||||
import { INSTANCE_NAME } from "@/graphql/config";
|
||||
const SentryFeedback = defineAsyncComponent(
|
||||
|
|
|
@ -23,11 +23,6 @@
|
|||
<script lang="ts" setup>
|
||||
import { localeShortWeekDayNames } from "@/utils/datetime";
|
||||
import { computed } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { locale } = useI18n({ useScope: "global" });
|
||||
|
||||
const localeConverted = locale.replace("_", "-");
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
|
@ -40,15 +35,15 @@ const props = withDefaults(
|
|||
const dateObj = computed<Date>(() => new Date(props.date));
|
||||
|
||||
const month = computed<string>(() =>
|
||||
dateObj.value.toLocaleString(localeConverted, { month: "short" })
|
||||
dateObj.value.toLocaleString(undefined, { month: "short" })
|
||||
);
|
||||
|
||||
const day = computed<string>(() =>
|
||||
dateObj.value.toLocaleString(localeConverted, { day: "numeric" })
|
||||
dateObj.value.toLocaleString(undefined, { day: "numeric" })
|
||||
);
|
||||
|
||||
const weekday = computed<string>(() =>
|
||||
dateObj.value.toLocaleString(localeConverted, { weekday: "short" })
|
||||
dateObj.value.toLocaleString(undefined, { weekday: "short" })
|
||||
);
|
||||
|
||||
const smallStyle = computed<string>(() => (props.small ? "1.2" : "2"));
|
||||
|
@ -64,7 +59,8 @@ div.datetime-container {
|
|||
height: calc(10px * var(--small));
|
||||
background: #f3425f;
|
||||
}
|
||||
.datetime-container-header .weekday {
|
||||
.datetime-container-header .weekday
|
||||
{
|
||||
font-size: calc(9px * var(--small));
|
||||
font-weight: bold;
|
||||
vertical-align: top;
|
||||
|
|
|
@ -23,10 +23,7 @@
|
|||
<div class="flex flex-col gap-1 mt-1">
|
||||
<p
|
||||
class="inline-flex gap-2 ml-auto"
|
||||
v-if="
|
||||
event.joinOptions !== EventJoinOptions.EXTERNAL &&
|
||||
!event.options.hideNumberOfParticipants
|
||||
"
|
||||
v-if="event.joinOptions !== EventJoinOptions.EXTERNAL"
|
||||
>
|
||||
<TicketConfirmationOutline />
|
||||
<router-link
|
||||
|
|
|
@ -12,31 +12,6 @@
|
|||
class="rounded-lg"
|
||||
:class="{ 'sm:w-full sm:max-w-[20rem]': mode === 'row' }"
|
||||
>
|
||||
<div
|
||||
class="-mt-3 h-0 mb-3 ltr:ml-0 rtl:mr-0 block relative z-10"
|
||||
:class="{
|
||||
'sm:hidden': mode === 'row',
|
||||
'calendar-simple': !isDifferentBeginsEndsDate,
|
||||
'calendar-double': isDifferentBeginsEndsDate,
|
||||
}"
|
||||
>
|
||||
<date-calendar-icon
|
||||
:small="true"
|
||||
v-if="!mergedOptions.hideDate"
|
||||
:date="event.beginsOn.toString()"
|
||||
/>
|
||||
<MenuDown
|
||||
:small="true"
|
||||
class="left-3 relative"
|
||||
v-if="!mergedOptions.hideDate && isDifferentBeginsEndsDate"
|
||||
/>
|
||||
<date-calendar-icon
|
||||
:small="true"
|
||||
v-if="!mergedOptions.hideDate && isDifferentBeginsEndsDate"
|
||||
:date="event.endsOn?.toString()"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<figure class="block relative pt-40">
|
||||
<lazy-image-wrapper
|
||||
:picture="event.picture"
|
||||
|
@ -74,12 +49,12 @@
|
|||
<div class="p-2 flex-auto" :class="{ 'sm:flex-1': mode === 'row' }">
|
||||
<div class="relative flex flex-col h-full">
|
||||
<div
|
||||
class="-mt-3 h-0 flex mb-3 ltr:ml-0 rtl:mr-0 items-end self-end"
|
||||
class="-mt-3 h-0 flex mb-3 ltr:ml-0 rtl:mr-0 items-end self-start"
|
||||
:class="{ 'sm:hidden': mode === 'row' }"
|
||||
>
|
||||
<start-time-icon
|
||||
<date-calendar-icon
|
||||
:small="true"
|
||||
v-if="!mergedOptions.hideDate && event.options.showStartTime"
|
||||
v-if="!mergedOptions.hideDate"
|
||||
:date="event.beginsOn.toString()"
|
||||
/>
|
||||
</div>
|
||||
|
@ -96,17 +71,8 @@
|
|||
<span
|
||||
class="text-gray-700 dark:text-white font-semibold hidden"
|
||||
:class="{ 'sm:block': mode === 'row' }"
|
||||
v-if="!isDifferentBeginsEndsDate"
|
||||
>{{ formatDateTimeWithCurrentLocale }}</span
|
||||
>
|
||||
<span
|
||||
class="text-gray-700 dark:text-white font-semibold hidden"
|
||||
:class="{ 'sm:block': mode === 'row' }"
|
||||
v-if="isDifferentBeginsEndsDate"
|
||||
>{{ formatBeginsOnDateWithCurrentLocale }}
|
||||
<ArrowRightThin :small="true" style="display: ruby" />
|
||||
{{ formatEndsOnDateWithCurrentLocale }}</span
|
||||
>
|
||||
<div class="w-full flex flex-col justify-between h-full">
|
||||
<h2
|
||||
class="mt-0 mb-2 text-2xl line-clamp-3 font-bold text-violet-3 dark:text-white"
|
||||
|
@ -196,16 +162,6 @@
|
|||
</div>
|
||||
</LinkOrRouterLink>
|
||||
</template>
|
||||
<style scoped>
|
||||
.calendar-simple {
|
||||
bottom: -117px;
|
||||
left: 5px;
|
||||
}
|
||||
.calendar-double {
|
||||
bottom: -45px;
|
||||
left: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
|
@ -216,8 +172,6 @@ import {
|
|||
} from "@/types/event.model";
|
||||
import DateCalendarIcon from "@/components/Event/DateCalendarIcon.vue";
|
||||
import StartTimeIcon from "@/components/Event/StartTimeIcon.vue";
|
||||
import ArrowRightThin from "vue-material-design-icons/ArrowRightThin.vue";
|
||||
import MenuDown from "vue-material-design-icons/MenuDown.vue";
|
||||
import LazyImageWrapper from "@/components/Image/LazyImageWrapper.vue";
|
||||
import { EventStatus } from "@/types/enums";
|
||||
import RouteName from "../../router/name";
|
||||
|
@ -227,7 +181,7 @@ import { computed, inject } from "vue";
|
|||
import MobilizonTag from "@/components/TagElement.vue";
|
||||
import AccountCircle from "vue-material-design-icons/AccountCircle.vue";
|
||||
import Video from "vue-material-design-icons/Video.vue";
|
||||
import { formatDateForEvent, formatDateTimeForEvent } from "@/utils/datetime";
|
||||
import { formatDateTimeForEvent } from "@/utils/datetime";
|
||||
import type { Locale } from "date-fns";
|
||||
import LinkOrRouterLink from "../core/LinkOrRouterLink.vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
@ -269,28 +223,6 @@ const actorAvatarURL = computed<string | null>(() =>
|
|||
|
||||
const dateFnsLocale = inject<Locale>("dateFnsLocale");
|
||||
|
||||
const isDifferentBeginsEndsDate = computed(() => {
|
||||
if (!dateFnsLocale) return;
|
||||
const beginsOnStr = formatDateForEvent(
|
||||
new Date(props.event.beginsOn),
|
||||
dateFnsLocale
|
||||
);
|
||||
const endsOnStr = props.event.endsOn
|
||||
? formatDateForEvent(new Date(props.event.endsOn), dateFnsLocale)
|
||||
: null;
|
||||
return endsOnStr && endsOnStr != beginsOnStr;
|
||||
});
|
||||
|
||||
const formatBeginsOnDateWithCurrentLocale = computed(() => {
|
||||
if (!dateFnsLocale) return;
|
||||
return formatDateForEvent(new Date(props.event.beginsOn), dateFnsLocale);
|
||||
});
|
||||
|
||||
const formatEndsOnDateWithCurrentLocale = computed(() => {
|
||||
if (!dateFnsLocale) return;
|
||||
return formatDateForEvent(new Date(props.event.endsOn), dateFnsLocale);
|
||||
});
|
||||
|
||||
const formatDateTimeWithCurrentLocale = computed(() => {
|
||||
if (!dateFnsLocale) return;
|
||||
return formatDateTimeForEvent(new Date(props.event.beginsOn), dateFnsLocale);
|
||||
|
|
|
@ -115,7 +115,7 @@ const props = withDefaults(
|
|||
|
||||
const { t } = useI18n({ useScope: "global" });
|
||||
|
||||
const showLocalTimezone = ref(false);
|
||||
const showLocalTimezone = ref(true);
|
||||
|
||||
const timezoneToShow = computed((): string | undefined => {
|
||||
if (showLocalTimezone.value) {
|
||||
|
|
|
@ -5,22 +5,17 @@
|
|||
:style="`--small: ${smallStyle}`"
|
||||
>
|
||||
<div class="starttime-container-content font-semibold">
|
||||
<Clock class="clock-icon" /><time :datetime="dateObj.toISOString()">{{
|
||||
time
|
||||
<Clock class="clock-icon"/><time :datetime="dateObj.toISOString()">{{
|
||||
time
|
||||
}}</time>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { localeShortWeekDayNames } from "@/utils/datetime";
|
||||
import { computed } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
import Clock from "vue-material-design-icons/ClockTimeTenOutline.vue";
|
||||
|
||||
const { locale } = useI18n({ useScope: "global" });
|
||||
|
||||
const localeConverted = locale.replace("_", "-");
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
date: string;
|
||||
|
@ -32,10 +27,7 @@ const props = withDefaults(
|
|||
const dateObj = computed<Date>(() => new Date(props.date));
|
||||
|
||||
const time = computed<string>(() =>
|
||||
dateObj.value.toLocaleTimeString(localeConverted, {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
})
|
||||
dateObj.value.toLocaleTimeString(undefined, { hour: "2-digit", minute: "2-digit" })
|
||||
);
|
||||
|
||||
const smallStyle = computed<string>(() => (props.small ? "0.9" : "2"));
|
||||
|
@ -47,11 +39,11 @@ div.starttime-container {
|
|||
box-shadow: 0 0 12px rgba(0, 0, 0, 0.2);
|
||||
padding: 0.25rem 0.25rem;
|
||||
font-size: calc(1rem * var(--small));
|
||||
}
|
||||
}
|
||||
|
||||
.clock-icon {
|
||||
vertical-align: middle;
|
||||
padding-right: 0.2rem;
|
||||
display: inline-block;
|
||||
}
|
||||
.clock-icon {
|
||||
vertical-align: middle;
|
||||
padding-right: 0.2rem;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
</template>
|
||||
<o-taginput
|
||||
:modelValue="tagsStrings"
|
||||
@update:modelValue="updateTags"
|
||||
@remove="remove"
|
||||
@add="add"
|
||||
:data="filteredTags"
|
||||
:allow-autocomplete="true"
|
||||
:allow-new="true"
|
||||
|
@ -93,6 +94,17 @@ const filteredTags = computed((): ITag[] => {
|
|||
);
|
||||
});
|
||||
|
||||
// TODO It seems that '@update:modelValue="updateTags"' does not works anymore...
|
||||
// so temporarily call the function updateTags() at remove and add tag event
|
||||
// https://github.com/oruga-ui/oruga/issues/967
|
||||
function remove() {
|
||||
updateTags(tagsStrings.value);
|
||||
}
|
||||
|
||||
function add() {
|
||||
updateTags(tagsStrings.value);
|
||||
}
|
||||
|
||||
const updateTags = (newTagsStrings: string[]) => {
|
||||
const tagEntities = newTagsStrings.map((tag: string | ITag) => {
|
||||
if (typeof tag !== "string") {
|
||||
|
|
|
@ -16,7 +16,7 @@ import { useGroup } from "@/composition/apollo/group";
|
|||
import { displayName } from "@/types/actor";
|
||||
import { computed } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useHead } from "@/utils/head";
|
||||
import { useHead } from "@unhead/vue";
|
||||
|
||||
const props = defineProps<{
|
||||
preferredUsername: string;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<template>
|
||||
<section
|
||||
v-if="promotedCategories.length > 1"
|
||||
class="mx-auto container flex flex-wrap items-center justify-center gap-3 md:gap-5 my-3"
|
||||
>
|
||||
<CategoryCard
|
||||
|
@ -11,6 +10,7 @@
|
|||
:imageLazy="false"
|
||||
/>
|
||||
<router-link
|
||||
v-if="promotedCategories.length > 0"
|
||||
:to="{ name: RouteName.CATEGORIES }"
|
||||
class="flex items-end brightness-85 h-36 w-36 md:h-52 md:w-52 rounded-lg font-semibold text-lg md:text-xl p-4 text-white bg-gradient-to-r from-pink-500 via-red-500 to-yellow-500 hover:text-slate-200"
|
||||
>
|
||||
|
@ -47,17 +47,13 @@ const eventCategoryLabel = (categoryId: string): string | undefined => {
|
|||
return eventCategories.value?.find(({ id }) => categoryId == id)?.label;
|
||||
};
|
||||
|
||||
const promotedCategories = computed((): CategoryStatsModel[] | null => {
|
||||
const relevant_categories = categoryStats.value.filter(
|
||||
({ key, number }) =>
|
||||
key !== "MEETING" && number >= 1 && categoriesWithPictures.includes(key)
|
||||
);
|
||||
|
||||
if (relevant_categories.length <= 1) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return shuffle(relevant_categories)
|
||||
const promotedCategories = computed((): CategoryStatsModel[] => {
|
||||
return shuffle(
|
||||
categoryStats.value.filter(
|
||||
({ key, number }) =>
|
||||
key !== "MEETING" && number >= 1 && categoriesWithPictures.includes(key)
|
||||
)
|
||||
)
|
||||
.map(({ key, number }) => ({
|
||||
key,
|
||||
number,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<form
|
||||
id="search-anchor"
|
||||
class="container mx-auto my-3 px-2 flex flex-wrap flex-col sm:flex-row items-stretch gap-2 text-center justify-center dark:text-slate-100"
|
||||
class="container mx-auto my-3 flex flex-wrap flex-row items-stretch gap-2 text-center items-center justify-center dark:text-slate-100"
|
||||
role="search"
|
||||
@submit.prevent="submit"
|
||||
>
|
||||
|
@ -25,12 +25,6 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { IAddress } from "@/types/address.model";
|
||||
import { AddressSearchType } from "@/types/enums";
|
||||
import {
|
||||
addressToLocation,
|
||||
getLocationFromLocal,
|
||||
storeLocationInLocal,
|
||||
} from "@/utils/location";
|
||||
import { computed, defineAsyncComponent } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
|
@ -44,7 +38,6 @@ const props = defineProps<{
|
|||
location: IAddress | null;
|
||||
locationDefaultText?: string | null;
|
||||
search: string;
|
||||
fromLocalStorage?: boolean | false;
|
||||
}>();
|
||||
|
||||
const router = useRouter();
|
||||
|
@ -58,19 +51,10 @@ const emit = defineEmits<{
|
|||
|
||||
const location = computed({
|
||||
get(): IAddress | null {
|
||||
if (props.location) {
|
||||
return props.location;
|
||||
}
|
||||
if (props.fromLocalStorage) {
|
||||
return getLocationFromLocal();
|
||||
}
|
||||
return null;
|
||||
return props.location;
|
||||
},
|
||||
set(newLocation: IAddress | null) {
|
||||
emit("update:location", newLocation);
|
||||
if (props.fromLocalStorage) {
|
||||
storeLocationInLocal(newLocation);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -85,7 +69,12 @@ const search = computed({
|
|||
|
||||
const submit = () => {
|
||||
emit("submit");
|
||||
const { lat, lon } = addressToLocation(location.value);
|
||||
const lat = location.value?.geom
|
||||
? parseFloat(location.value?.geom?.split(";")?.[1])
|
||||
: undefined;
|
||||
const lon = location.value?.geom
|
||||
? parseFloat(location.value?.geom?.split(";")?.[0])
|
||||
: undefined;
|
||||
router.push({
|
||||
name: RouteName.SEARCH,
|
||||
query: {
|
||||
|
|
|
@ -1,14 +1,26 @@
|
|||
<template>
|
||||
<section class="container mx-auto px-2 my-3">
|
||||
<h1 class="dark:text-white font-bold">
|
||||
{{ config.slogan ?? t("Gather ⋅ Organize ⋅ Mobilize") }}
|
||||
</h1>
|
||||
|
||||
<p class="dark:text-white mb-2">{{ config.description }}</p>
|
||||
<p class="dark:text-white mb-2">{{ config.slogan }}</p>
|
||||
<!-- We don't invite to find other instances yet -->
|
||||
<!-- <p v-if="!config.registrationsOpen">
|
||||
{{ t("This instance isn't opened to registrations, but you can register on other instances.") }}
|
||||
</p>-->
|
||||
<div class="flex flex-wrap gap-2 items-center">
|
||||
<o-button
|
||||
variant="primary"
|
||||
tag="router-link"
|
||||
:to="{ name: RouteName.REGISTER }"
|
||||
v-if="config.registrationsOpen"
|
||||
>{{ t("Create an account") }}</o-button
|
||||
>
|
||||
<!-- We don't invite to find other instances yet -->
|
||||
<!-- <o-button v-else variant="link" tag="a" href="https://joinmastodon.org">{{ t('Find an instance') }}</o-button> -->
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { IConfig } from "@/types/config.model";
|
||||
import RouteName from "@/router/name";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
defineProps<{
|
||||
|
|
|
@ -11,11 +11,8 @@
|
|||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
import { IMedia } from "@/types/media.model";
|
||||
import { useDefaultPicture } from "@/composition/apollo/config";
|
||||
import LazyImage from "../Image/LazyImage.vue";
|
||||
|
||||
const { defaultPicture } = useDefaultPicture();
|
||||
|
||||
const DEFAULT_CARD_URL = "/img/mobilizon_default_card.png";
|
||||
const DEFAULT_BLURHASH = "MCHKI4El-P-U}+={R-WWoes,Iu-P=?R,xD";
|
||||
const DEFAULT_WIDTH = 630;
|
||||
|
@ -41,9 +38,6 @@ const props = withDefaults(
|
|||
|
||||
const pictureOrDefault = computed(() => {
|
||||
if (props.picture === null) {
|
||||
if (defaultPicture?.value?.url) {
|
||||
return defaultPicture.value;
|
||||
}
|
||||
return DEFAULT_PICTURE;
|
||||
}
|
||||
return {
|
||||
|
|
|
@ -19,16 +19,34 @@
|
|||
</div>
|
||||
<slot name="subtitle" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="grid auto-rows-[1fr] gap-x-2 gap-y-2 grid-cols-[repeat(auto-fill,_minmax(250px,_1fr))] justify-items-center"
|
||||
>
|
||||
<slot name="content" />
|
||||
<!-- <div class="hidden sm:block" v-show="showScrollLeftButton">
|
||||
<button
|
||||
@click="scrollLeft"
|
||||
class="absolute inset-y-0 my-auto z-10 rounded-full bg-white dark:bg-transparent w-10 h-10 border border-shadowColor -left-5 ml-2"
|
||||
>
|
||||
<span class=""><</span>
|
||||
</button>
|
||||
</div> -->
|
||||
<div class="overflow-hidden">
|
||||
<div
|
||||
class="multi-card-event"
|
||||
>
|
||||
<slot name="content" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="hidden sm:block" v-show="showScrollRightButton">
|
||||
<button
|
||||
@click="scrollRight"
|
||||
class="absolute inset-y-0 my-auto z-10 rounded-full bg-white dark:bg-transparent w-10 h-10 border border-shadowColor -right-5 mr-2"
|
||||
>
|
||||
<span class="">></span>
|
||||
</button>
|
||||
</div> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, onUnmounted, ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
withDefaults(
|
||||
|
@ -42,6 +60,55 @@ withDefaults(
|
|||
const emit = defineEmits(["doGeoLoc"]);
|
||||
|
||||
const { t } = useI18n({ useScope: "global" });
|
||||
|
||||
// const showScrollRightButton = ref(true);
|
||||
// const showScrollLeftButton = ref(false);
|
||||
|
||||
// const scrollContainer = ref<any>();
|
||||
|
||||
// const scrollHandler = () => {
|
||||
// if (scrollContainer.value) {
|
||||
// showScrollRightButton.value =
|
||||
// scrollContainer.value.scrollLeft <
|
||||
// scrollContainer.value.scrollWidth - scrollContainer.value.clientWidth;
|
||||
// showScrollLeftButton.value = scrollContainer.value.scrollLeft > 0;
|
||||
// }
|
||||
// };
|
||||
|
||||
// const doScroll = (e: Event, left: number) => {
|
||||
// e.preventDefault();
|
||||
// if (scrollContainer.value) {
|
||||
// scrollContainer.value.scrollBy({
|
||||
// left,
|
||||
// behavior: "smooth",
|
||||
// });
|
||||
// }
|
||||
// };
|
||||
|
||||
// const scrollLeft = (e: Event) => {
|
||||
// doScroll(e, -300);
|
||||
// };
|
||||
|
||||
// const scrollRight = (e: Event) => {
|
||||
// doScroll(e, 300);
|
||||
// };
|
||||
|
||||
// const scrollHorizontalToVertical = (evt: WheelEvent) => {
|
||||
// evt.deltaY > 0 ? doScroll(evt, 300) : doScroll(evt, -300);
|
||||
// };
|
||||
|
||||
// onMounted(async () => {
|
||||
// scrollContainer.value.addEventListener("wheel", scrollHorizontalToVertical);
|
||||
// });
|
||||
|
||||
// onUnmounted(() => {
|
||||
// if (scrollContainer.value) {
|
||||
// scrollContainer.value.removeEventListener(
|
||||
// "wheel",
|
||||
// scrollHorizontalToVertical
|
||||
// );
|
||||
// }
|
||||
// });
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
@ -1,36 +1,20 @@
|
|||
<template>
|
||||
<close-content
|
||||
class="container mx-auto px-2"
|
||||
:suggestGeoloc="false"
|
||||
v-show="loading || (events && events.total > 0)"
|
||||
:suggestGeoloc="suggestGeoloc"
|
||||
v-on="attrs"
|
||||
@doGeoLoc="emit('doGeoLoc')"
|
||||
:doingGeoloc="doingGeoloc"
|
||||
>
|
||||
<template #title>
|
||||
<template v-if="userLocation?.name">
|
||||
{{
|
||||
t("Incoming events nearby {position}", {
|
||||
position: userLocation?.name,
|
||||
})
|
||||
}}
|
||||
<template v-if="userLocationName">
|
||||
{{ t("Events nearby {position}", { position: userLocationName }) }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ t("Incoming events") }}
|
||||
{{ t("Events close to you") }}
|
||||
</template>
|
||||
</template>
|
||||
<template #subtitle>
|
||||
<div v-if="!loading && events.total == 0">
|
||||
<template v-if="userLocation?.name">
|
||||
{{
|
||||
t(
|
||||
"No events found nearby {position}. Try removing your position to see all events!",
|
||||
{ position: userLocation?.name }
|
||||
)
|
||||
}}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ t("No events found") }}
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<skeleton-event-result
|
||||
v-for="i in 6"
|
||||
|
@ -44,36 +28,25 @@
|
|||
:key="event.uuid"
|
||||
/>
|
||||
<more-content
|
||||
v-if="userLocation?.name && userLocation?.lat && userLocation?.lon"
|
||||
v-if="userLocationName && userLocation?.lat && userLocation?.lon"
|
||||
:to="{
|
||||
name: RouteName.SEARCH,
|
||||
query: {
|
||||
locationName: userLocation?.name,
|
||||
locationName: userLocationName,
|
||||
lat: userLocation.lat?.toString(),
|
||||
lon: userLocation.lon?.toString(),
|
||||
contentType: 'ALL',
|
||||
contentType: 'EVENTS',
|
||||
distance: `${distance}_km`,
|
||||
},
|
||||
}"
|
||||
:picture="userLocation?.picture"
|
||||
>
|
||||
{{
|
||||
t("View more events and activities around {position}", {
|
||||
position: userLocation?.name,
|
||||
t("View more events around {position}", {
|
||||
position: userLocationName,
|
||||
})
|
||||
}}
|
||||
</more-content>
|
||||
<more-content
|
||||
v-else
|
||||
:to="{
|
||||
name: RouteName.SEARCH,
|
||||
query: {
|
||||
contentType: 'ALL',
|
||||
},
|
||||
}"
|
||||
>
|
||||
{{ t("View more events and activities") }}
|
||||
</more-content>
|
||||
</template>
|
||||
</close-content>
|
||||
</template>
|
||||
|
@ -82,56 +55,76 @@
|
|||
import { LocationType } from "../../types/user-location.model";
|
||||
import MoreContent from "./MoreContent.vue";
|
||||
import CloseContent from "./CloseContent.vue";
|
||||
import { watch, computed, useAttrs } from "vue";
|
||||
import { FETCH_EVENTS } from "@/graphql/event";
|
||||
import { computed, onMounted, useAttrs } from "vue";
|
||||
import { SEARCH_EVENTS } from "@/graphql/search";
|
||||
import { IEvent } from "@/types/event.model";
|
||||
import { useQuery } from "@vue/apollo-composable";
|
||||
import { useLazyQuery } from "@vue/apollo-composable";
|
||||
import EventCard from "../Event/EventCard.vue";
|
||||
import { Paginate } from "@/types/paginate";
|
||||
import SkeletonEventResult from "../Event/SkeletonEventResult.vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { coordsToGeoHash } from "@/utils/location";
|
||||
import { roundToNearestMinute } from "@/utils/datetime";
|
||||
import RouteName from "@/router/name";
|
||||
import { EventSortField, SortDirection } from "@/types/enums";
|
||||
|
||||
const props = defineProps<{
|
||||
userLocation: LocationType;
|
||||
doingGeoloc?: boolean;
|
||||
}>();
|
||||
defineEmits(["doGeoLoc"]);
|
||||
const emit = defineEmits(["doGeoLoc"]);
|
||||
|
||||
const EVENT_PAGE_LIMIT = 12;
|
||||
|
||||
const { t } = useI18n({ useScope: "global" });
|
||||
const attrs = useAttrs();
|
||||
|
||||
const userLocation = computed(() => props.userLocation);
|
||||
|
||||
const geoHash = computed(() => {
|
||||
console.debug("userLocation updated", userLocation.value);
|
||||
const geo = coordsToGeoHash(userLocation.value.lat, userLocation.value.lon);
|
||||
console.debug("geohash:", geo);
|
||||
return geo;
|
||||
const userLocationName = computed(() => {
|
||||
return userLocation.value?.name;
|
||||
});
|
||||
const suggestGeoloc = computed(() => userLocation.value?.isIPLocation);
|
||||
|
||||
const distance = computed<number>(() =>
|
||||
userLocation.value?.isIPLocation ? 150 : 25
|
||||
const geoHash = computed(() =>
|
||||
coordsToGeoHash(props.userLocation.lat, props.userLocation.lon)
|
||||
);
|
||||
|
||||
const eventsQuery = useQuery<{
|
||||
const distance = computed<number>(() => (suggestGeoloc.value ? 150 : 25));
|
||||
|
||||
const now = computed(() => roundToNearestMinute(new Date()));
|
||||
|
||||
const searchEnabled = computed(() => geoHash.value != undefined);
|
||||
|
||||
const {
|
||||
result: eventsResult,
|
||||
loading: loadingEvents,
|
||||
load: load,
|
||||
} = useLazyQuery<{
|
||||
searchEvents: Paginate<IEvent>;
|
||||
}>(FETCH_EVENTS, () => ({
|
||||
orderBy: EventSortField.BEGINS_ON,
|
||||
direction: SortDirection.ASC,
|
||||
longevents: false,
|
||||
location: geoHash.value,
|
||||
radius: distance.value,
|
||||
limit: 93,
|
||||
}));
|
||||
}>(
|
||||
SEARCH_EVENTS,
|
||||
() => ({
|
||||
location: geoHash.value,
|
||||
beginsOn: now.value,
|
||||
endsOn: undefined,
|
||||
radius: distance.value,
|
||||
eventPage: 1,
|
||||
limit: EVENT_PAGE_LIMIT,
|
||||
type: "IN_PERSON",
|
||||
}),
|
||||
() => ({
|
||||
enabled: searchEnabled.value,
|
||||
fetchPolicy: "cache-first",
|
||||
})
|
||||
);
|
||||
|
||||
const events = computed(
|
||||
() => eventsQuery.result.value?.events ?? { elements: [], total: 0 }
|
||||
() => eventsResult.value?.searchEvents ?? { elements: [], total: 0 }
|
||||
);
|
||||
watch(events, (e) => console.debug("events: ", e));
|
||||
|
||||
const loading = computed(() => props.doingGeoloc || eventsQuery.loading.value);
|
||||
watch(loading, (l) => console.debug("loading: ", l));
|
||||
onMounted(async () => {
|
||||
await load();
|
||||
});
|
||||
|
||||
const loading = computed(() => props.doingGeoloc || loadingEvents.value);
|
||||
</script>
|
||||
|
|
|
@ -6,7 +6,18 @@
|
|||
v-on="attrs"
|
||||
>
|
||||
<template #title>
|
||||
{{ t("Agenda") }}
|
||||
{{ t("Last published events") }}
|
||||
</template>
|
||||
<template #subtitle>
|
||||
<i18n-t
|
||||
class="text-slate-700 dark:text-slate-300"
|
||||
tag="p"
|
||||
keypath="On {instance} and other federated instances"
|
||||
>
|
||||
<template #instance>
|
||||
<b>{{ instanceName }}</b>
|
||||
</template>
|
||||
</i18n-t>
|
||||
</template>
|
||||
<template #content>
|
||||
<skeleton-event-result
|
||||
|
@ -58,9 +69,8 @@ const attrs = useAttrs();
|
|||
const { result: resultEvents, loading: loadingEvents } = useQuery<{
|
||||
events: Paginate<IEvent>;
|
||||
}>(FETCH_EVENTS, {
|
||||
orderBy: EventSortField.BEGINS_ON,
|
||||
direction: SortDirection.ASC,
|
||||
longevents: false,
|
||||
orderBy: EventSortField.INSERTED_AT,
|
||||
direction: SortDirection.DESC,
|
||||
});
|
||||
const events = computed(
|
||||
() => resultEvents.value?.events ?? { total: 0, elements: [] }
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
class="bg-black border-gray-200 px-2 sm:px-4 py-2.5 dark:bg-gray-50"
|
||||
id="navbar"
|
||||
>
|
||||
<div class="container mx-auto flex flex-wrap items-center gap-2 sm:gap-4">
|
||||
<div
|
||||
class="container mx-auto flex flex-wrap items-center mx-auto gap-2 sm:gap-4"
|
||||
>
|
||||
<router-link
|
||||
:to="{ name: RouteName.HOME }"
|
||||
class="flex items-center"
|
||||
|
@ -173,34 +175,10 @@
|
|||
v-model:location="location"
|
||||
/>
|
||||
|
||||
<li class="m-auto" v-if="islongEvents">
|
||||
<router-link
|
||||
:to="{
|
||||
name: RouteName.SEARCH,
|
||||
query: { contentType: 'SHORTEVENTS' },
|
||||
}"
|
||||
class="block py-2 pr-4 pl-3 text-gray-50 border-b border-gray-100 hover:bg-gray-950 md:hover:bg-transparent md:border-0 md:hover:text-mbz-purple-700 md:p-0 dark:text-gray-950 md:dark:hover:text-gray-950 dark:hover:bg-gray-950 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700"
|
||||
>{{ t("Events") }}</router-link
|
||||
>
|
||||
</li>
|
||||
<li class="m-auto" v-else>
|
||||
<router-link
|
||||
:to="{ name: RouteName.SEARCH, query: { contentType: 'EVENTS' } }"
|
||||
class="block py-2 pr-4 pl-3 text-gray-50 border-b border-gray-100 hover:bg-gray-950 md:hover:bg-transparent md:border-0 md:hover:text-mbz-purple-700 md:p-0 dark:text-gray-950 md:dark:hover:text-gray-950 dark:hover:bg-gray-950 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700"
|
||||
>{{ t("Events") }}</router-link
|
||||
>
|
||||
</li>
|
||||
<li class="m-auto">
|
||||
<router-link
|
||||
:to="{ name: RouteName.SEARCH, query: { contentType: 'GROUPS' } }"
|
||||
class="block py-2 pr-4 pl-3 text-gray-50 border-b border-gray-100 hover:bg-gray-950 md:hover:bg-transparent md:border-0 md:hover:text-mbz-purple-700 md:p-0 dark:text-gray-950 md:dark:hover:text-gray-950 dark:hover:bg-gray-950 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700"
|
||||
>{{ t("Groups") }}</router-link
|
||||
>
|
||||
</li>
|
||||
<li class="m-auto">
|
||||
<router-link
|
||||
:to="{ name: RouteName.EVENT_CALENDAR }"
|
||||
class="block py-2 pr-4 pl-3 text-gray-50 border-b border-gray-100 hover:bg-gray-950 md:hover:bg-transparent md:border-0 md:hover:text-mbz-purple-700 md:p-0 dark:text-gray-950 md:dark:hover:text-gray-950 dark:hover:bg-gray-950 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700"
|
||||
class="block py-2 pr-4 pl-3 text-gray-50 border-b border-gray-100 hover:bg-zinc-50 md:hover:bg-transparent md:border-0 md:hover:text-mbz-purple-700 md:p-0 dark:text-gray-950 md:dark:hover:text-gray-900 dark:hover:bg-zinc-700 md:dark:hover:text-gray-900 md:dark:hover:bg-transparent dark:border-gray-700"
|
||||
>{{ t("Calendar") }}</router-link
|
||||
>
|
||||
</li>
|
||||
|
@ -263,15 +241,10 @@ import {
|
|||
import { useMutation } from "@vue/apollo-composable";
|
||||
import { UPDATE_DEFAULT_ACTOR } from "@/graphql/actor";
|
||||
import { changeIdentity } from "@/utils/identity";
|
||||
import {
|
||||
useRegistrationConfig,
|
||||
useIsLongEvents,
|
||||
} from "@/composition/apollo/config";
|
||||
import { useRegistrationConfig } from "@/composition/apollo/config";
|
||||
import { useOruga } from "@oruga-ui/oruga-next";
|
||||
import SearchFields from "@/components/Home/SearchFields.vue";
|
||||
|
||||
const { islongEvents } = useIsLongEvents();
|
||||
|
||||
const { currentUser } = useCurrentUserClient();
|
||||
const { currentActor } = useCurrentActorClient();
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useHead } from "@/utils/head";
|
||||
import { useHead } from "@unhead/vue";
|
||||
import { computed, inject, ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useMutation } from "@vue/apollo-composable";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<footer
|
||||
class="bg-violet-2 color-secondary flex flex-col items-center py-3 px-3"
|
||||
class="bg-zinc-900 color-secondary flex flex-col items-center py-2 px-3"
|
||||
ref="footer"
|
||||
>
|
||||
<ul
|
||||
|
@ -79,11 +79,15 @@ import { saveLocaleData } from "@/utils/auth";
|
|||
import { loadLanguageAsync } from "@/utils/i18n";
|
||||
import RouteName from "../router/name";
|
||||
import langs from "../i18n/langs.json";
|
||||
import { watch } from "vue";
|
||||
import { computed, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { locale, t } = useI18n({ useScope: "global" });
|
||||
|
||||
const random = computed((): number => {
|
||||
return Math.floor(Math.random() * 4) + 1;
|
||||
});
|
||||
|
||||
watch(locale, async () => {
|
||||
if (locale) {
|
||||
console.debug("Setting locale from footer");
|
||||
|
@ -96,9 +100,3 @@ const isLangSelected = (lang: string): boolean => {
|
|||
return lang === locale.value;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
footer > ul > li {
|
||||
margin: auto 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -45,7 +45,7 @@ import { LEAVE_EVENT } from "../../graphql/event";
|
|||
import { computed, ref, watchEffect } from "vue";
|
||||
import { useMutation } from "@vue/apollo-composable";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useHead } from "@/utils/head";
|
||||
import { useHead } from "@unhead/vue";
|
||||
import { IActor } from "@/types/actor";
|
||||
import { IEvent } from "@/types/event.model";
|
||||
import { useAnonymousActorId } from "@/composition/apollo/config";
|
||||
|
|
|
@ -70,7 +70,7 @@ import { CONFIRM_PARTICIPATION } from "../../graphql/event";
|
|||
import { computed, ref, watchEffect } from "vue";
|
||||
import { useMutation } from "@vue/apollo-composable";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useHead } from "@/utils/head";
|
||||
import { useHead } from "@unhead/vue";
|
||||
|
||||
const { t } = useI18n({ useScope: "global" });
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<script lang="ts" setup>
|
||||
import RedirectWithAccount from "@/components/Utils/RedirectWithAccount.vue";
|
||||
import { useFetchEvent } from "@/composition/apollo/event";
|
||||
import { useHead } from "@/utils/head";
|
||||
import { useHead } from "@unhead/vue";
|
||||
import { computed } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ import { useFetchEventBasic } from "@/composition/apollo/event";
|
|||
import { useAnonymousActorId } from "@/composition/apollo/config";
|
||||
import { computed, reactive, ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useHead } from "@/utils/head";
|
||||
import { useHead } from "@unhead/vue";
|
||||
import { useMutation } from "@vue/apollo-composable";
|
||||
|
||||
const error = ref<boolean | string>(false);
|
||||
|
|
|
@ -99,7 +99,7 @@ import { useFetchEvent } from "@/composition/apollo/event";
|
|||
import { useAnonymousParticipationConfig } from "@/composition/apollo/config";
|
||||
import { computed } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { useHead } from "@/utils/head";
|
||||
import { useHead } from "@unhead/vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const props = defineProps<{ uuid: string }>();
|
||||
|
|
|
@ -173,8 +173,6 @@ const icons: Record<string, () => Promise<any>> = {
|
|||
import(
|
||||
`../../../node_modules/vue-material-design-icons/CalendarRemove.vue`
|
||||
),
|
||||
CalendarStar: () =>
|
||||
import(`../../../node_modules/vue-material-design-icons/CalendarStar.vue`),
|
||||
FileDocumentEdit: () =>
|
||||
import(
|
||||
`../../../node_modules/vue-material-design-icons/FileDocumentEdit.vue`
|
||||
|
|
|
@ -4,15 +4,11 @@ import {
|
|||
ANONYMOUS_ACTOR_ID,
|
||||
ANONYMOUS_PARTICIPATION_CONFIG,
|
||||
ANONYMOUS_REPORTS_CONFIG,
|
||||
DEFAULT_PICTURE,
|
||||
DEMO_MODE,
|
||||
LONG_EVENTS,
|
||||
EVENT_CATEGORIES,
|
||||
EVENT_PARTICIPANTS,
|
||||
FEATURES,
|
||||
GEOCODING_AUTOCOMPLETE,
|
||||
COLORS,
|
||||
INSTANCE_LOGO,
|
||||
LOCATION,
|
||||
MAPS_TILES,
|
||||
REGISTRATIONS,
|
||||
|
@ -80,36 +76,6 @@ export function useInstanceName() {
|
|||
return { instanceName, error, loading };
|
||||
}
|
||||
|
||||
export function useInstanceLogoUrl() {
|
||||
const { result, error, loading } = useQuery<{
|
||||
config: Pick<IConfig, "instanceLogo">;
|
||||
}>(INSTANCE_LOGO);
|
||||
|
||||
const instanceLogoUrl = computed(
|
||||
() => result.value?.config?.instanceLogo?.url
|
||||
);
|
||||
return { instanceLogoUrl, error, loading };
|
||||
}
|
||||
|
||||
export function useColors() {
|
||||
const { result, error, loading } = useQuery<{
|
||||
config: Pick<IConfig, "primaryColor" | "secondaryColor">;
|
||||
}>(COLORS);
|
||||
|
||||
const primaryColor = computed(() => result.value?.config?.primaryColor);
|
||||
const secondaryColor = computed(() => result.value?.config?.secondaryColor);
|
||||
return { primaryColor, secondaryColor, error, loading };
|
||||
}
|
||||
|
||||
export function useDefaultPicture() {
|
||||
const { result, error, loading } = useQuery<{
|
||||
config: Pick<IConfig, "defaultPicture">;
|
||||
}>(DEFAULT_PICTURE);
|
||||
|
||||
const defaultPicture = computed(() => result.value?.config?.defaultPicture);
|
||||
return { defaultPicture, error, loading };
|
||||
}
|
||||
|
||||
export function useAnonymousActorId() {
|
||||
const { result, error, loading } = useQuery<{
|
||||
config: Pick<IConfig, "anonymous">;
|
||||
|
@ -222,15 +188,6 @@ export function useIsDemoMode() {
|
|||
return { isDemoMode, error, loading };
|
||||
}
|
||||
|
||||
export function useIsLongEvents() {
|
||||
const { result, error, loading } = useQuery<{
|
||||
config: Pick<IConfig, "longEvents">;
|
||||
}>(LONG_EVENTS);
|
||||
|
||||
const islongEvents = computed(() => result.value?.config.longEvents);
|
||||
return { islongEvents, error, loading };
|
||||
}
|
||||
|
||||
export function useAnalytics() {
|
||||
const { result, error, loading } = useQuery<{
|
||||
config: Pick<IConfig, "analytics">;
|
||||
|
|
|
@ -2,7 +2,6 @@ import { IDENTITIES, REGISTER_PERSON } from "@/graphql/actor";
|
|||
import {
|
||||
CURRENT_USER_CLIENT,
|
||||
LOGGED_USER,
|
||||
LOGGED_USER_LOCATION,
|
||||
SET_USER_SETTINGS,
|
||||
UPDATE_USER_LOCALE,
|
||||
USER_SETTINGS,
|
||||
|
@ -52,20 +51,6 @@ export function useUserSettings() {
|
|||
return { loggedUser, error, loading };
|
||||
}
|
||||
|
||||
export function useUserLocation() {
|
||||
const {
|
||||
result: userSettingsResult,
|
||||
error,
|
||||
loading,
|
||||
onResult,
|
||||
} = useQuery<{ loggedUser: IUser }>(LOGGED_USER_LOCATION);
|
||||
|
||||
const location = computed(
|
||||
() => userSettingsResult.value?.loggedUser.settings.location
|
||||
);
|
||||
return { location, error, loading, onResult };
|
||||
}
|
||||
|
||||
export async function doUpdateSetting(
|
||||
variables: Record<string, unknown>
|
||||
): Promise<void> {
|
||||
|
|