Merge branch 'bugs' into 'main'
Mobilizon 2.0.0-rc.3 Closes #936 See merge request framasoft/mobilizon!1120
This commit is contained in:
commit
2d6fa93906
11
CHANGELOG.md
11
CHANGELOG.md
@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## 2.0.0-rc.3 - 2021-11-22
|
||||||
|
|
||||||
|
This lists changes since 2.0.0-rc.3. Please read the [UPGRADE.md](https://framagit.org/framasoft/mobilizon/-/blob/main/UPGRADE.md#upgrading-from-13-to-20) file as well.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed path to exports in production
|
||||||
|
- Fixed padding below truncated title of event cards
|
||||||
|
- Fixed exports that weren't enabled in Docker
|
||||||
|
- Fixed error page when event end date is null
|
||||||
|
|
||||||
## 2.0.0-rc.2 - 2021-11-22
|
## 2.0.0-rc.2 - 2021-11-22
|
||||||
|
|
||||||
This lists changes since 2.0.0-rc.1. Please read the [UPGRADE.md](https://framagit.org/framasoft/mobilizon/-/blob/main/UPGRADE.md#upgrading-from-13-to-20) file as well.
|
This lists changes since 2.0.0-rc.1. Please read the [UPGRADE.md](https://framagit.org/framasoft/mobilizon/-/blob/main/UPGRADE.md#upgrading-from-13-to-20) file as well.
|
||||||
|
15
UPGRADE.md
15
UPGRADE.md
@ -8,7 +8,7 @@ You are already using latest Elixir version in the release tarball and Docker im
|
|||||||
|
|
||||||
### Source install
|
### Source install
|
||||||
|
|
||||||
**Elixir 1.12 and Erlang OTP 22 are now required**. If your distribution doesn't provide these versions (which is likely), you must uninstall them and install [Elixir](https://github.com/asdf-vm/asdf-elixir) through the [ASDF tool](https://asdf-vm.com/).
|
**Elixir 1.12 and Erlang OTP 22 are now required**. If your distribution or the repositories from Erlang Solutions don't provide these versions, you need to uninstall the current versions and install [Elixir](https://github.com/asdf-vm/asdf-elixir) through the [ASDF tool](https://asdf-vm.com/).
|
||||||
|
|
||||||
## Geographic timezone data
|
## Geographic timezone data
|
||||||
|
|
||||||
@ -61,6 +61,17 @@ In both cases, ~700Mio of disk will be used. You may use the following configura
|
|||||||
config :tz_world, data_dir: "/some/place"
|
config :tz_world, data_dir: "/some/place"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Exports folder
|
||||||
|
|
||||||
|
Create the folder for default CSV export:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo -u mobilizon mkdir -p /var/lib/mobilizon/uploads/exports/csv
|
||||||
|
```
|
||||||
|
|
||||||
|
This path can be configured, see [the dedicated docs page about this](https://docs.joinmobilizon.org/administration/configure/exports/).
|
||||||
|
Files in this folder are temporary and are cleaned once an hour.
|
||||||
|
|
||||||
## New optional dependencies
|
## New optional dependencies
|
||||||
|
|
||||||
These are optional, installing them will allow Mobilizon to export to PDF and ODS as well. Mobilizon 2.0 allows to export the participant list, but more is planned.
|
These are optional, installing them will allow Mobilizon to export to PDF and ODS as well. Mobilizon 2.0 allows to export the participant list, but more is planned.
|
||||||
@ -73,7 +84,7 @@ New optional Python dependencies:
|
|||||||
* `weasyprint` for PDF export (with [a few extra dependencies](https://doc.courtbouillon.org/weasyprint/stable/first_steps.html))
|
* `weasyprint` for PDF export (with [a few extra dependencies](https://doc.courtbouillon.org/weasyprint/stable/first_steps.html))
|
||||||
* `pyexcel-ods3` for ODS export (no extra dependencies)
|
* `pyexcel-ods3` for ODS export (no extra dependencies)
|
||||||
|
|
||||||
Both can be installed through pip. You need to enable exports for PDF and ODS in the configuration afterwards. Read [the dedicated docs page about this]() (*upcoming*).
|
Both can be installed through pip. You need to enable and configure exports for PDF and ODS in the configuration afterwards. Read [the dedicated docs page about this](https://docs.joinmobilizon.org/administration/configure/exports/).
|
||||||
|
|
||||||
# Upgrading from 1.0 to 1.1
|
# Upgrading from 1.0 to 1.1
|
||||||
|
|
||||||
|
@ -329,6 +329,7 @@ config :mobilizon, Mobilizon.Service.Notifier.Email, enabled: true
|
|||||||
config :mobilizon, Mobilizon.Service.Notifier.Push, enabled: true
|
config :mobilizon, Mobilizon.Service.Notifier.Push, enabled: true
|
||||||
|
|
||||||
config :mobilizon, :exports,
|
config :mobilizon, :exports,
|
||||||
|
path: "/var/lib/mobilizon/uploads/exports",
|
||||||
formats: [
|
formats: [
|
||||||
Mobilizon.Service.Export.Participants.CSV
|
Mobilizon.Service.Export.Participants.CSV
|
||||||
]
|
]
|
||||||
|
@ -94,6 +94,8 @@ config :mobilizon, Mobilizon.Web.Auth.Guardian,
|
|||||||
|
|
||||||
config :mobilizon, Mobilizon.Web.Upload.Uploader.Local, uploads: "uploads"
|
config :mobilizon, Mobilizon.Web.Upload.Uploader.Local, uploads: "uploads"
|
||||||
|
|
||||||
|
config :mobilizon, :exports, path: "uploads/exports"
|
||||||
|
|
||||||
config :tz_world, data_dir: "_build/dev/lib/tz_world/priv"
|
config :tz_world, data_dir: "_build/dev/lib/tz_world/priv"
|
||||||
|
|
||||||
config :mobilizon, :anonymous,
|
config :mobilizon, :anonymous,
|
||||||
|
@ -68,5 +68,13 @@ config :geolix,
|
|||||||
config :mobilizon, Mobilizon.Web.Upload.Uploader.Local,
|
config :mobilizon, Mobilizon.Web.Upload.Uploader.Local,
|
||||||
uploads: System.get_env("MOBILIZON_UPLOADS", "/var/lib/mobilizon/uploads")
|
uploads: System.get_env("MOBILIZON_UPLOADS", "/var/lib/mobilizon/uploads")
|
||||||
|
|
||||||
|
config :mobilizon, :exports,
|
||||||
|
path: System.get_env("MOBILIZON_UPLOADS_EXPORTS", "/var/lib/mobilizon/uploads/exports"),
|
||||||
|
formats: [
|
||||||
|
Mobilizon.Service.Export.Participants.CSV,
|
||||||
|
Mobilizon.Service.Export.Participants.PDF,
|
||||||
|
Mobilizon.Service.Export.Participants.ODS
|
||||||
|
]
|
||||||
|
|
||||||
config :tz_world,
|
config :tz_world,
|
||||||
data_dir: System.get_env("MOBILIZON_TIMEZONES_DIR", "/var/lib/mobilizon/timezones")
|
data_dir: System.get_env("MOBILIZON_TIMEZONES_DIR", "/var/lib/mobilizon/timezones")
|
||||||
|
@ -60,6 +60,8 @@ config :mobilizon, Mobilizon.Web.Upload, filters: [], link_name: false
|
|||||||
|
|
||||||
config :mobilizon, Mobilizon.Web.Upload.Uploader.Local, uploads: "test/uploads"
|
config :mobilizon, Mobilizon.Web.Upload.Uploader.Local, uploads: "test/uploads"
|
||||||
|
|
||||||
|
config :mobilizon, :exports, path: "test/uploads/exports"
|
||||||
|
|
||||||
config :tz_world, data_dir: "_build/test/lib/tz_world/priv"
|
config :tz_world, data_dir: "_build/test/lib/tz_world/priv"
|
||||||
|
|
||||||
config :tesla, Mobilizon.Service.HTTP.ActivityPub,
|
config :tesla, Mobilizon.Service.HTTP.ActivityPub,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mobilizon",
|
"name": "mobilizon",
|
||||||
"version": "2.0.0-rc.2",
|
"version": "2.0.0-rc.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vue-cli-service serve",
|
||||||
|
@ -248,10 +248,13 @@ a.card {
|
|||||||
-webkit-line-clamp: 3;
|
-webkit-line-clamp: 3;
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding-bottom: 8px;
|
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content-end {
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.event-subtitle {
|
.event-subtitle {
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ const SHORT_TIME_FORMAT_OPTIONS: DateTimeFormatOptions = {
|
|||||||
|
|
||||||
function formatDateTimeString(
|
function formatDateTimeString(
|
||||||
value: string,
|
value: string,
|
||||||
timeZone: string | undefined = undefined,
|
timeZone: string | null | undefined = undefined,
|
||||||
showTime = true,
|
showTime = true,
|
||||||
dateFormat = "long"
|
dateFormat = "long"
|
||||||
): string {
|
): string {
|
||||||
@ -68,7 +68,7 @@ function formatDateTimeString(
|
|||||||
options = {
|
options = {
|
||||||
...options,
|
...options,
|
||||||
...(isLongFormat ? LONG_TIME_FORMAT_OPTIONS : SHORT_TIME_FORMAT_OPTIONS),
|
...(isLongFormat ? LONG_TIME_FORMAT_OPTIONS : SHORT_TIME_FORMAT_OPTIONS),
|
||||||
timeZone,
|
timeZone: timeZone || undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const format = new Intl.DateTimeFormat(locale(), options);
|
const format = new Intl.DateTimeFormat(locale(), options);
|
||||||
|
@ -4,9 +4,9 @@ defmodule Mobilizon.Service.Export.Participants.Common do
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.Actor
|
||||||
|
alias Mobilizon.{Config, Export}
|
||||||
alias Mobilizon.Events.Participant
|
alias Mobilizon.Events.Participant
|
||||||
alias Mobilizon.Events.Participant.Metadata
|
alias Mobilizon.Events.Participant.Metadata
|
||||||
alias Mobilizon.Export
|
|
||||||
alias Mobilizon.Storage.Repo
|
alias Mobilizon.Storage.Repo
|
||||||
import Mobilizon.Web.Gettext, only: [gettext: 1]
|
import Mobilizon.Web.Gettext, only: [gettext: 1]
|
||||||
|
|
||||||
@ -117,4 +117,13 @@ defmodule Mobilizon.Service.Export.Participants.Common do
|
|||||||
formats = Keyword.get(export_config, :formats, [])
|
formats = Keyword.get(export_config, :formats, [])
|
||||||
type in formats
|
type in formats
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@default_upload_path "uploads/exports/"
|
||||||
|
|
||||||
|
@spec export_path(String.t()) :: String.t()
|
||||||
|
def export_path(extension) do
|
||||||
|
[:exports, :path]
|
||||||
|
|> Config.get(@default_upload_path)
|
||||||
|
|> Path.join(extension)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -3,17 +3,21 @@ defmodule Mobilizon.Service.Export.Participants.CSV do
|
|||||||
Export a list of participants to CSV
|
Export a list of participants to CSV
|
||||||
"""
|
"""
|
||||||
|
|
||||||
alias Mobilizon.Events
|
alias Mobilizon.{Events, Export}
|
||||||
alias Mobilizon.Events.Event
|
alias Mobilizon.Events.Event
|
||||||
alias Mobilizon.Export
|
|
||||||
alias Mobilizon.Storage.Repo
|
alias Mobilizon.Storage.Repo
|
||||||
alias Mobilizon.Web.Gettext
|
alias Mobilizon.Web.Gettext
|
||||||
import Mobilizon.Web.Gettext, only: [gettext: 2]
|
import Mobilizon.Web.Gettext, only: [gettext: 2]
|
||||||
|
|
||||||
import Mobilizon.Service.Export.Participants.Common,
|
import Mobilizon.Service.Export.Participants.Common,
|
||||||
only: [save_upload: 5, columns: 0, to_list: 1, clean_exports: 2, export_enabled?: 1]
|
only: [
|
||||||
|
save_upload: 5,
|
||||||
@upload_path "uploads/exports/csv/"
|
columns: 0,
|
||||||
|
to_list: 1,
|
||||||
|
clean_exports: 2,
|
||||||
|
export_enabled?: 1,
|
||||||
|
export_path: 1
|
||||||
|
]
|
||||||
|
|
||||||
@extension "csv"
|
@extension "csv"
|
||||||
|
|
||||||
@ -26,7 +30,7 @@ defmodule Mobilizon.Service.Export.Participants.CSV do
|
|||||||
def export(%Event{id: event_id} = event, options \\ []) do
|
def export(%Event{id: event_id} = event, options \\ []) do
|
||||||
if ready?() do
|
if ready?() do
|
||||||
filename = "#{ShortUUID.encode!(Ecto.UUID.generate())}.csv"
|
filename = "#{ShortUUID.encode!(Ecto.UUID.generate())}.csv"
|
||||||
full_path = @upload_path <> filename
|
full_path = Path.join([export_path(@extension), filename])
|
||||||
|
|
||||||
file = File.open!(full_path, [:write, :utf8])
|
file = File.open!(full_path, [:write, :utf8])
|
||||||
|
|
||||||
@ -80,7 +84,7 @@ defmodule Mobilizon.Service.Export.Participants.CSV do
|
|||||||
"""
|
"""
|
||||||
@spec clean_exports :: :ok
|
@spec clean_exports :: :ok
|
||||||
def clean_exports do
|
def clean_exports do
|
||||||
clean_exports("csv", @upload_path)
|
clean_exports("csv", export_path(@extension))
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec dependencies_ok? :: boolean
|
@spec dependencies_ok? :: boolean
|
||||||
|
@ -10,9 +10,14 @@ defmodule Mobilizon.Service.Export.Participants.ODS do
|
|||||||
import Mobilizon.Web.Gettext, only: [gettext: 2]
|
import Mobilizon.Web.Gettext, only: [gettext: 2]
|
||||||
|
|
||||||
import Mobilizon.Service.Export.Participants.Common,
|
import Mobilizon.Service.Export.Participants.Common,
|
||||||
only: [save_upload: 5, to_list: 1, clean_exports: 2, columns: 0, export_enabled?: 1]
|
only: [
|
||||||
|
save_upload: 5,
|
||||||
@upload_path "uploads/exports/ods/"
|
to_list: 1,
|
||||||
|
clean_exports: 2,
|
||||||
|
columns: 0,
|
||||||
|
export_enabled?: 1,
|
||||||
|
export_path: 1
|
||||||
|
]
|
||||||
|
|
||||||
@extension "ods"
|
@extension "ods"
|
||||||
|
|
||||||
@ -25,7 +30,7 @@ defmodule Mobilizon.Service.Export.Participants.ODS do
|
|||||||
def export(%Event{id: event_id} = event, options \\ []) do
|
def export(%Event{id: event_id} = event, options \\ []) do
|
||||||
if ready?() do
|
if ready?() do
|
||||||
filename = "#{ShortUUID.encode!(Ecto.UUID.generate())}.ods"
|
filename = "#{ShortUUID.encode!(Ecto.UUID.generate())}.ods"
|
||||||
full_path = @upload_path <> filename
|
full_path = Path.join([export_path(@extension), filename])
|
||||||
|
|
||||||
case Repo.transaction(
|
case Repo.transaction(
|
||||||
fn ->
|
fn ->
|
||||||
@ -84,7 +89,7 @@ defmodule Mobilizon.Service.Export.Participants.ODS do
|
|||||||
"""
|
"""
|
||||||
@spec clean_exports :: :ok
|
@spec clean_exports :: :ok
|
||||||
def clean_exports do
|
def clean_exports do
|
||||||
clean_exports("ods", @upload_path)
|
clean_exports(@extension, export_path(@extension))
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec dependencies_ok? :: boolean
|
@spec dependencies_ok? :: boolean
|
||||||
|
@ -12,9 +12,14 @@ defmodule Mobilizon.Service.Export.Participants.PDF do
|
|||||||
import Mobilizon.Web.Gettext, only: [gettext: 2]
|
import Mobilizon.Web.Gettext, only: [gettext: 2]
|
||||||
|
|
||||||
import Mobilizon.Service.Export.Participants.Common,
|
import Mobilizon.Service.Export.Participants.Common,
|
||||||
only: [save_upload: 5, columns: 0, to_list: 1, clean_exports: 2, export_enabled?: 1]
|
only: [
|
||||||
|
save_upload: 5,
|
||||||
@upload_path "uploads/exports/pdf/"
|
columns: 0,
|
||||||
|
to_list: 1,
|
||||||
|
clean_exports: 2,
|
||||||
|
export_enabled?: 1,
|
||||||
|
export_path: 1
|
||||||
|
]
|
||||||
|
|
||||||
@extension "pdf"
|
@extension "pdf"
|
||||||
|
|
||||||
@ -27,7 +32,7 @@ defmodule Mobilizon.Service.Export.Participants.PDF do
|
|||||||
def export(%Event{id: event_id} = event, options \\ []) do
|
def export(%Event{id: event_id} = event, options \\ []) do
|
||||||
if ready?() do
|
if ready?() do
|
||||||
filename = "#{ShortUUID.encode!(Ecto.UUID.generate())}.pdf"
|
filename = "#{ShortUUID.encode!(Ecto.UUID.generate())}.pdf"
|
||||||
full_path = @upload_path <> filename
|
full_path = Path.join([export_path(@extension), filename])
|
||||||
|
|
||||||
case Repo.transaction(
|
case Repo.transaction(
|
||||||
fn ->
|
fn ->
|
||||||
@ -98,7 +103,7 @@ defmodule Mobilizon.Service.Export.Participants.PDF do
|
|||||||
"""
|
"""
|
||||||
@spec clean_exports :: :ok
|
@spec clean_exports :: :ok
|
||||||
def clean_exports do
|
def clean_exports do
|
||||||
clean_exports("pdf", @upload_path)
|
clean_exports(@extension, export_path(@extension))
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec dependencies_ok? :: boolean
|
@spec dependencies_ok? :: boolean
|
||||||
|
@ -6,7 +6,7 @@ defmodule Mobilizon.Web.ExportController do
|
|||||||
plug(:put_layout, false)
|
plug(:put_layout, false)
|
||||||
action_fallback(Mobilizon.Web.FallbackController)
|
action_fallback(Mobilizon.Web.FallbackController)
|
||||||
alias Mobilizon.Export
|
alias Mobilizon.Export
|
||||||
import Mobilizon.Service.Export.Participants.Common, only: [enabled_formats: 0]
|
import Mobilizon.Service.Export.Participants.Common, only: [enabled_formats: 0, export_path: 1]
|
||||||
import Mobilizon.Web.Gettext, only: [dgettext: 3]
|
import Mobilizon.Web.Gettext, only: [dgettext: 3]
|
||||||
|
|
||||||
# sobelow_skip ["Traversal.SendDownload"]
|
# sobelow_skip ["Traversal.SendDownload"]
|
||||||
@ -15,7 +15,7 @@ defmodule Mobilizon.Web.ExportController do
|
|||||||
if format in enabled_formats() do
|
if format in enabled_formats() do
|
||||||
case Export.get_export(file, "event_participants", format) do
|
case Export.get_export(file, "event_participants", format) do
|
||||||
%Export{file_name: file_name, file_path: file_path} ->
|
%Export{file_name: file_name, file_path: file_path} ->
|
||||||
local_path = "uploads/exports/#{format}/#{file_path}"
|
local_path = Path.join(export_path(format), file_path)
|
||||||
# We're using encode: false to disable escaping the filename with URI.encode_www_form/1
|
# We're using encode: false to disable escaping the filename with URI.encode_www_form/1
|
||||||
# but it may introduce an security issue if the event title wasn't properly sanitized
|
# but it may introduce an security issue if the event title wasn't properly sanitized
|
||||||
# https://github.com/phoenixframework/phoenix/pull/3344
|
# https://github.com/phoenixframework/phoenix/pull/3344
|
||||||
|
Loading…
Reference in New Issue
Block a user