mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-03-15 12:29:16 +01:00
Merge branch 'dev' for release 5.7.1
This commit is contained in:
commit
3993c9a8d4
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,5 +1,15 @@
|
||||
# Changelog Fab-manager
|
||||
|
||||
## v5.7.1 2023 February 20
|
||||
|
||||
- Fix a bug: timezone is ignored while configuring calendar opening/closing time
|
||||
- Fix a bug: unable to configure RAILS_LOCALE to fr-CA
|
||||
- Fix a bug: unable to fix availabilities for events
|
||||
- Fix a bug: unable to start Fab-manager with message: maximum must be a nonnegative Integer
|
||||
- Fix a bug: unable to export orders statistics
|
||||
- Fix a bug: invalid shell coloring during setup
|
||||
- [TODO DEPLOY] `fablab:maintenance:clean_availabilities`
|
||||
|
||||
## v5.7.0 2023 February 17
|
||||
|
||||
- Report user's prepaid packs in the dashboard
|
||||
|
@ -17,7 +17,7 @@ class API::SettingsController < API::ApiController
|
||||
error = SettingService.check_before_update({ name: params[:name], value: setting_params[:value] })
|
||||
render status: :unprocessable_entity, json: { error: error } and return if error
|
||||
|
||||
if @setting.save && @setting.history_values.create(value: setting_params[:value], invoicing_profile: current_user.invoicing_profile)
|
||||
if SettingService.save_and_update(@setting, setting_params[:value], current_user)
|
||||
SettingService.run_after_update([@setting])
|
||||
render status: :ok
|
||||
else
|
||||
@ -39,11 +39,8 @@ class API::SettingsController < API::ApiController
|
||||
error = SettingService.check_before_update(setting)
|
||||
if error
|
||||
db_setting.errors.add(:-, "#{I18n.t("settings.#{setting[:name]}")}: #{error}")
|
||||
elsif db_setting.save
|
||||
if db_setting.value != setting[:value] &&
|
||||
db_setting.history_values.create(value: setting[:value], invoicing_profile: current_user.invoicing_profile)
|
||||
updated_settings.push(db_setting)
|
||||
end
|
||||
elsif db_setting.value != setting[:value] && SettingService.save_and_update(db_setting, setting[:value], current_user)
|
||||
updated_settings.push(db_setting)
|
||||
end
|
||||
else
|
||||
db_setting.errors.add(:-, "#{I18n.t("settings.#{setting[:name]}")}: #{I18n.t('settings.locked_setting')}")
|
||||
|
@ -8,5 +8,5 @@ class SupportingDocumentFile < ApplicationRecord
|
||||
belongs_to :supporting_document_type
|
||||
belongs_to :user
|
||||
|
||||
validates :attachment, file_size: { maximum: ENV.fetch('MAX_SUPPORTING_DOCUMENT_FILE_SIZE', 5.megabytes.to_i) }
|
||||
validates :attachment, file_size: { maximum: ENV.fetch('MAX_SUPPORTING_DOCUMENT_FILE_SIZE', 5.megabytes).to_i }
|
||||
end
|
||||
|
@ -18,6 +18,16 @@ class SettingService
|
||||
check_home_scss(setting)
|
||||
end
|
||||
|
||||
# @param setting [Setting]
|
||||
# @param value [String]
|
||||
# @param operator [User]
|
||||
def save_and_update(setting, value, operator)
|
||||
return false unless setting.save
|
||||
|
||||
val = parse_value(setting.name, value)
|
||||
setting.history_values.create(value: val, invoicing_profile: operator.invoicing_profile)
|
||||
end
|
||||
|
||||
# @param settings [Array<Setting>]
|
||||
def run_after_update(settings)
|
||||
update_theme_stylesheet(settings)
|
||||
@ -35,6 +45,14 @@ class SettingService
|
||||
|
||||
private
|
||||
|
||||
# @param setting [String]
|
||||
# @param value [String]
|
||||
def parse_value(setting, value)
|
||||
return value unless %w[booking_window_start booking_window_end].include?(setting)
|
||||
|
||||
Time.zone.parse(value)
|
||||
end
|
||||
|
||||
# rebuild the theme stylesheet
|
||||
# @param settings [Array<Setting>]
|
||||
def update_theme_stylesheet(settings)
|
||||
@ -44,6 +62,7 @@ class SettingService
|
||||
end
|
||||
|
||||
# validate that the provided SCSS has a valid syntax
|
||||
# @param setting [Hash{Symbol->String}]
|
||||
def check_home_scss(setting)
|
||||
return nil unless setting[:name] == 'home_css'
|
||||
|
||||
|
@ -42,7 +42,7 @@ class StatisticsExportService
|
||||
end
|
||||
|
||||
# rubocop:disable Style/DocumentDynamicEvalDefinition
|
||||
%w[account event machine project subscription training space].each do |path|
|
||||
%w[account event machine project subscription training space order].each do |path|
|
||||
class_eval %{
|
||||
def export_#{path}(export)
|
||||
|
||||
|
@ -14,9 +14,9 @@ class StatisticsExportWorker
|
||||
service = StatisticsExportService.new
|
||||
method_name = "export_#{export.export_type}"
|
||||
|
||||
unless %w[account event machine project subscription training space global].include?(export.export_type) &&
|
||||
unless %w[account event machine project subscription training space order global].include?(export.export_type) &&
|
||||
service.respond_to?(method_name)
|
||||
return
|
||||
raise TypeError("Invalid statistics export type #{export.export_type}")
|
||||
end
|
||||
|
||||
service.public_send(method_name, export)
|
||||
@ -24,6 +24,5 @@ class StatisticsExportWorker
|
||||
NotificationCenter.call type: :notify_admin_export_complete,
|
||||
receiver: export.user,
|
||||
attached_object: export
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -3,7 +3,7 @@
|
||||
# List of all allowed values for RAILS_LOCALE
|
||||
I18n.config.available_locales += %i[de de-AT de-CH de-DE
|
||||
en en-AU en-CA en-GB en-IE en-IN en-NZ en-US en-ZA
|
||||
fr fa-CA fr-CH fr-CM fr-FR
|
||||
fr fr-CA fr-CH fr-CM fr-FR
|
||||
es es-419 es-AR es-CL es-CO es-CR es-DO es-EC es-ES es-MX es-PA es-PE es-US es-VE
|
||||
no
|
||||
pt pt-BR
|
||||
@ -11,7 +11,6 @@ I18n.config.available_locales += %i[de de-AT de-CH de-DE
|
||||
# we allow the Zulu locale (zu) as it is used for In-Context translation
|
||||
# @see https://support.crowdin.com/in-context-localization/
|
||||
|
||||
|
||||
#
|
||||
# /!\ ALL locales SHOULD be configured accordingly with the default_locale. /!\
|
||||
#
|
||||
|
@ -376,6 +376,7 @@ de:
|
||||
statistics_subscription: "der Abonnementstatistiken"
|
||||
statistics_training: "der Schulungsstatistiken"
|
||||
statistics_space: "der Raumstatistiken"
|
||||
statistics_order: "of statistics about store orders"
|
||||
users_members: "der Mitgliederliste"
|
||||
users_subscriptions: "der Abonnementliste"
|
||||
users_reservations: "der Reservierungsliste"
|
||||
|
@ -376,6 +376,7 @@ en:
|
||||
statistics_subscription: "of subscription statistics"
|
||||
statistics_training: "of statistics about trainings"
|
||||
statistics_space: "of statistics about spaces"
|
||||
statistics_order: "of statistics about store orders"
|
||||
users_members: "of the members' list"
|
||||
users_subscriptions: "of the subscriptions' list"
|
||||
users_reservations: "of the reservations' list"
|
||||
|
@ -376,6 +376,7 @@ es:
|
||||
statistics_subscription: "de estadísticas de suscripción"
|
||||
statistics_training: "de estadísticas de cursos"
|
||||
statistics_space: "de estadísticas sobre espacios"
|
||||
statistics_order: "of statistics about store orders"
|
||||
users_members: "de la lista de miembros"
|
||||
users_subscriptions: "de la lista de suscripciones"
|
||||
users_reservations: "de la lista de reservas"
|
||||
|
@ -376,6 +376,7 @@ fr:
|
||||
statistics_subscription: "des statistiques d'abonnements"
|
||||
statistics_training: "des statistiques sur les formations"
|
||||
statistics_space: "des statistiques sur les espaces"
|
||||
statistics_order: "des statistiques des commandes de la boutique"
|
||||
users_members: "de la liste des membres"
|
||||
users_subscriptions: "de la liste des abonnements"
|
||||
users_reservations: "de la liste des réservations"
|
||||
|
@ -376,6 +376,7 @@
|
||||
statistics_subscription: "for abonnementsstatistikk"
|
||||
statistics_training: "av statistikk om opplæringer"
|
||||
statistics_space: "av statistikk om plasser/rom"
|
||||
statistics_order: "of statistics about store orders"
|
||||
users_members: "fra medlemslisten"
|
||||
users_subscriptions: "fra abonnementslisten"
|
||||
users_reservations: "fra reservasjonslisten"
|
||||
|
@ -376,6 +376,7 @@ pt:
|
||||
statistics_subscription: "de estatísticas de assinatura"
|
||||
statistics_training: "de estatísticas sobre treinamentos"
|
||||
statistics_space: "as estatísticas sobre reserva de espaços"
|
||||
statistics_order: "of statistics about store orders"
|
||||
users_members: "da lista de membros"
|
||||
users_subscriptions: "da lista de assinaturas"
|
||||
users_reservations: "da lista de reservas"
|
||||
|
@ -376,6 +376,7 @@ zu:
|
||||
statistics_subscription: "crwdns3647:0crwdne3647:0"
|
||||
statistics_training: "crwdns3649:0crwdne3649:0"
|
||||
statistics_space: "crwdns3651:0crwdne3651:0"
|
||||
statistics_order: "crwdns37387:0crwdne37387:0"
|
||||
users_members: "crwdns3653:0crwdne3653:0"
|
||||
users_subscriptions: "crwdns3655:0crwdne3655:0"
|
||||
users_reservations: "crwdns3657:0crwdne3657:0"
|
||||
|
@ -196,8 +196,7 @@ Please, be aware that **the configured locale will imply the CURRENCY symbol use
|
||||
|
||||
_Eg.: configuring **es-ES** will set the currency symbol to **€** but **es-MX** will set **$** as currency symbol, so setting the `RAILS_LOCALE` to simple **es** (without country indication) will probably not do what you expect._
|
||||
|
||||
Available values: `en, en-AU-CA, en-GB, en-IE, en-IN, en-NZ, en-US, en-ZA, fr, fa-CA, fr-CH, fr-CM, fr-FR, es, es-419, es-AR, es-CL, es-CO, es-CR, es-DO,
|
||||
es-EC, es-ES, es-MX, es-MX, es-PA, es-PE, es-US, es-VE, no, pt, pt-BR, zu`.
|
||||
Available values: `en, en-AU-CA, en-GB, en-IE, en-IN, en-NZ, en-US, en-ZA, fr, fr-CA, fr-CH, fr-CM, fr-FR, es, es-419, es-AR, es-CL, es-CO, es-CR, es-DO, es-EC, es-ES, es-MX, es-MX, es-PA, es-PE, es-US, es-VE, no, pt, pt-BR, zu`.
|
||||
When not defined, it defaults to **en**.
|
||||
|
||||
If your locale is not present in that list or any locale doesn't have your exact expectations, please open a pull request to share your modifications with the community and obtain a rebuilt docker image.
|
||||
|
@ -12,15 +12,17 @@ namespace :fablab do
|
||||
other_slots = Slot.where(availability_id: slot.availability_id)
|
||||
reservations = SlotsReservation.where(slot_id: other_slots.map(&:id))
|
||||
|
||||
type = available_type(reservations)
|
||||
a = Availability.new(
|
||||
id: slot.availability_id,
|
||||
start_at: other_slots.group('id').select('min(start_at) as min').first[:min],
|
||||
end_at: other_slots.group('id').select('max(end_at) as max').first[:max],
|
||||
available_type: available_type(reservations),
|
||||
available_type: type,
|
||||
machine_ids: machines_ids(reservations, slot.availability_id),
|
||||
space_ids: space_ids(reservations, slot.availability_id),
|
||||
training_ids: training_ids(reservations, slot.availability_id)
|
||||
)
|
||||
create_mock_event(reservations, slot.availability_id) if type == 'event' && a.event.nil?
|
||||
raise StandardError, "unable to save availability for slot #{slot.id}: #{a.errors.full_messages}" unless a.save(validate: false)
|
||||
end
|
||||
end
|
||||
@ -85,4 +87,32 @@ namespace :fablab do
|
||||
|
||||
[]
|
||||
end
|
||||
|
||||
# @param reservations [ActiveRecord::Relation<SlotsReservation>]
|
||||
# @param availability_id [Number]
|
||||
def create_mock_event(reservations, availability_id)
|
||||
model = find_similar_event(reservations)
|
||||
invoice_item = reservations.first&.reservation&.invoice_items&.find_by(main: true)
|
||||
Event.create!(
|
||||
title: model&.title || invoice_item&.description,
|
||||
description: model&.description || invoice_item&.description,
|
||||
category: model&.category || Category.first,
|
||||
availability_id: availability_id
|
||||
)
|
||||
end
|
||||
|
||||
# @param reservations [ActiveRecord::Relation<SlotsReservation>]
|
||||
# @return [Event,NilClass]
|
||||
def find_similar_event(reservations)
|
||||
reservations.each do |reservation|
|
||||
reservation.reservation.invoice_items.each do |invoice_item|
|
||||
words = invoice_item.description.split
|
||||
(0..words.count).each do |w|
|
||||
try_title = words[0..words.count - w].join(' ')
|
||||
event = Event.find_by("title LIKE '#{try_title}%'")
|
||||
return event unless event.nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -139,6 +139,11 @@ namespace :fablab do
|
||||
puts '-> Done'
|
||||
end
|
||||
|
||||
desc 'Remove ghost availabilities and slots'
|
||||
task clean_availabilities: :environment do
|
||||
Availability.where(available_type: 'unknown').destroy_all
|
||||
end
|
||||
|
||||
def dates_from_args(args)
|
||||
year = args.year || Time.current.year
|
||||
month = args.month || Time.current.month
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "fab-manager",
|
||||
"version": "5.7.0",
|
||||
"version": "5.7.1",
|
||||
"description": "Fab-manager is the FabLab management solution. It provides a comprehensive, web-based, open-source tool to simplify your administrative tasks and your marker's projects.",
|
||||
"keywords": [
|
||||
"fablab",
|
||||
|
@ -384,7 +384,7 @@ configure_env_file()
|
||||
var_doc=$(get_md_anchor "$doc" "$variable")
|
||||
current=$(grep "$variable=" "$FABMANAGER_PATH/config/env")
|
||||
echo "$var_doc" | bat --file-name "$variable" --language md --color=always
|
||||
printf -- "- \e[1mCurrent value: %s\e[21m\n- New value? (leave empty to keep the current value)\n" "$current"
|
||||
printf -- "- \e[1mCurrent value: %s\e[0m\n- New value? (leave empty to keep the current value)\n" "$current"
|
||||
read -rep " > " value </dev/tty
|
||||
if [ "$value" != "" ]; then
|
||||
esc_val=$(printf '%s\n' "$value" | sed -e 's/\//\\\//g')
|
||||
@ -399,7 +399,7 @@ configure_env_file()
|
||||
# if DEFAULT_PROTOCOL was set to http, ALLOW_INSECURE_HTTP is probably required
|
||||
if grep "^DEFAULT_PROTOCOL=http$" "$FABMANAGER_PATH/config/env" 1>/dev/null; then
|
||||
get_md_anchor "$doc" "ALLOW_INSECURE_HTTP" | bat --file-name "ALLOW_INSECURE_HTTP" --language md --color=always
|
||||
printf "You have set \e[1mDEFAULT_PROTOCOL\e[21m to \e[1mhttp\e[21m.\n"
|
||||
printf "You have set \e[1mDEFAULT_PROTOCOL\e[0m to \e[1mhttp\e[21m.\n"
|
||||
read -rp "Do you want to allow insecure HTTP? (Y/n) " confirm </dev/tty
|
||||
if [ "$confirm" != "n" ]; then
|
||||
sed -i.bak "s/ALLOW_INSECURE_HTTP=.*/ALLOW_INSECURE_HTTP=true/g" "$FABMANAGER_PATH/config/env"
|
||||
|
Loading…
x
Reference in New Issue
Block a user