Merge branch 'bugs' into 'main'

Mobilizon 2.0.0-rc.3

Closes #936

See merge request framasoft/mobilizon!1120
This commit is contained in:
Thomas Citharel 2021-11-22 19:28:08 +00:00
commit 2d6fa93906
15 changed files with 88 additions and 27 deletions

View File

@ -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.

View File

@ -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

View File

@ -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
] ]

View File

@ -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,

View File

@ -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")

View File

@ -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,

View File

@ -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",

View File

@ -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;
} }

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,7 +1,7 @@
defmodule Mobilizon.Mixfile do defmodule Mobilizon.Mixfile do
use Mix.Project use Mix.Project
@version "2.0.0-rc.2" @version "2.0.0-rc.3"
def project do def project do
[ [