1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2024-11-28 09:24:24 +01:00

Merge branch 'dev' for release 4.7.9

This commit is contained in:
Sylvain 2021-05-17 14:13:37 +02:00
commit c7527d06dd
52 changed files with 623 additions and 188 deletions

View File

@ -1,5 +1,34 @@
# Changelog Fab-manager
## v4.7.9 2021 May 17
- Updated dependency to OpenLab
- Updated i18next to 19.9.3
- Prevent the worker from crashing if OpenLab is not reachable in dev
- Allow setting multiple themes for a single event
- Increased the width of the input field for the prices of the events
- Script to run a rails command with ease in production (`run.fab.mn`)
- Fix a bug: invalid currency in notifications for locales with region (eg. fr-CM)
- Fix a bug: the notification sent to the project author when a collaborator has confirmed his participation is not sent
- Fix a bug: the event themes are not kept when editing the event again
- Fix a bug: the count of successfully updated events was not correct
- Fix a bug: german watermark was missing
- Fix a bug: invoices are not generated in test/development for locale with region (eg. fr-CA)
- Fix a bug: cannot access to "about" page on small devices
- Fix a bug: "about" page shows a non-functional menu icon
- Fix a bug: responsiveness of the "about" page title
Fix a bug: unable to change the slots durations for a new availability
- Fix a bug: some invoices does not have the name of the user
- Fix a bug: unable to sort invoices by date
- Fix a security issue: updated underscore to 1.12.1 to fix [CVE-2021-23358](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-23358)
- Fix a security issue: updated lodash to 4.17.21 to fix [CVE-2021-23337](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-23337)
- Fix a security issue: updated url-parse to 1.5.1 to fix [CVE-2021-27515](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-27515)
- Fix a security issue: updated hosted-git-info to 2.8.9 to fix [CVE-2021-23362](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-23362)
- Fix a security issue: updated codemirror to 5.58.2 to fix [CVE-2020-7760](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-7760)
- Fix a security issue: updated rails to 5.2.6 to fix [CVE-2021-22904](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-22904)
- Fix a security issue: updated react-i18next to 11.8.15 to fix [CVE-2021-23346](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-23346)
- [TODO DEPLOY] `rails fablab:fix:invoices_without_names`
## v4.7.8 2021 April 02
- Updated mimemagic to 0.3.10 to fix [a build issue](https://github.com/mimemagicrb/mimemagic/issues/139)

View File

@ -4,46 +4,46 @@ GEM
Ascii85 (1.0.3)
aasm (5.0.8)
concurrent-ruby (~> 1.0)
actioncable (5.2.4.5)
actionpack (= 5.2.4.5)
actioncable (5.2.6)
actionpack (= 5.2.6)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailer (5.2.4.5)
actionpack (= 5.2.4.5)
actionview (= 5.2.4.5)
activejob (= 5.2.4.5)
actionmailer (5.2.6)
actionpack (= 5.2.6)
actionview (= 5.2.6)
activejob (= 5.2.6)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (5.2.4.5)
actionview (= 5.2.4.5)
activesupport (= 5.2.4.5)
actionpack (5.2.6)
actionview (= 5.2.6)
activesupport (= 5.2.6)
rack (~> 2.0, >= 2.0.8)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionpack-page_caching (1.2.2)
actionpack (>= 5.0.0)
actionview (5.2.4.5)
activesupport (= 5.2.4.5)
actionview (5.2.6)
activesupport (= 5.2.6)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
active_record_query_trace (1.7)
activejob (5.2.4.5)
activesupport (= 5.2.4.5)
activejob (5.2.6)
activesupport (= 5.2.6)
globalid (>= 0.3.6)
activemodel (5.2.4.5)
activesupport (= 5.2.4.5)
activerecord (5.2.4.5)
activemodel (= 5.2.4.5)
activesupport (= 5.2.4.5)
activemodel (5.2.6)
activesupport (= 5.2.6)
activerecord (5.2.6)
activemodel (= 5.2.6)
activesupport (= 5.2.6)
arel (>= 9.0)
activestorage (5.2.4.5)
actionpack (= 5.2.4.5)
activerecord (= 5.2.4.5)
marcel (~> 0.3.1)
activesupport (5.2.4.5)
activestorage (5.2.6)
actionpack (= 5.2.6)
activerecord (= 5.2.6)
marcel (~> 1.0.0)
activesupport (5.2.6)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
@ -154,10 +154,10 @@ GEM
hashery (2.1.2)
hashie (4.1.0)
htmlentities (4.3.4)
httparty (0.18.0)
httparty (0.18.1)
mime-types (~> 3.0)
multi_xml (>= 0.5.2)
i18n (1.8.9)
i18n (1.8.10)
concurrent-ruby (~> 1.0)
icalendar (2.5.3)
ice_cube (~> 0.16)
@ -188,25 +188,24 @@ GEM
listen (3.0.8)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
loofah (2.9.0)
loofah (2.9.1)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
mini_mime (>= 0.1.1)
marcel (0.3.3)
mimemagic (~> 0.3.2)
marcel (1.0.1)
message_format (0.0.6)
twitter_cldr (~> 5.0)
method_source (1.0.0)
mime-types (3.3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2020.0512)
mimemagic (0.3.10)
mime-types-data (3.2021.0225)
mimemagic (0.4.3)
nokogiri (~> 1)
rake
mini_magick (4.10.1)
mini_mime (1.0.2)
mini_portile2 (2.5.0)
mini_mime (1.1.0)
mini_portile2 (2.5.1)
minitest (5.14.4)
minitest-reporters (1.4.2)
ansi
@ -217,8 +216,8 @@ GEM
multi_json (1.14.1)
multi_xml (0.6.0)
multipart-post (2.1.1)
nio4r (2.5.5)
nokogiri (1.11.1)
nio4r (2.5.7)
nokogiri (1.11.3)
mini_portile2 (~> 2.5.0)
racc (~> 1.4)
notify_with (0.0.2)
@ -241,7 +240,7 @@ GEM
omniauth-rails_csrf_protection (0.1.2)
actionpack (>= 4.2)
omniauth (>= 1.3.1)
openlab_ruby (0.0.4)
openlab_ruby (0.0.5)
httparty (~> 0.13)
orm_adapter (0.5.0)
parallel (1.19.1)
@ -278,18 +277,18 @@ GEM
rack-test (1.1.0)
rack (>= 1.0, < 3)
railroady (1.5.3)
rails (5.2.4.5)
actioncable (= 5.2.4.5)
actionmailer (= 5.2.4.5)
actionpack (= 5.2.4.5)
actionview (= 5.2.4.5)
activejob (= 5.2.4.5)
activemodel (= 5.2.4.5)
activerecord (= 5.2.4.5)
activestorage (= 5.2.4.5)
activesupport (= 5.2.4.5)
rails (5.2.6)
actioncable (= 5.2.6)
actionmailer (= 5.2.6)
actionpack (= 5.2.6)
actionview (= 5.2.6)
activejob (= 5.2.6)
activemodel (= 5.2.6)
activerecord (= 5.2.6)
activestorage (= 5.2.6)
activesupport (= 5.2.6)
bundler (>= 1.3.0)
railties (= 5.2.4.5)
railties (= 5.2.6)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
@ -303,9 +302,9 @@ GEM
rails_stdout_logging
rails_serve_static_assets (0.0.5)
rails_stdout_logging (0.0.5)
railties (5.2.4.5)
actionpack (= 5.2.4.5)
activesupport (= 5.2.4.5)
railties (5.2.6)
actionpack (= 5.2.6)
activesupport (= 5.2.6)
method_source
rake (>= 0.8.7)
thor (>= 0.19.0, < 2.0)

View File

@ -64,7 +64,9 @@ class API::EventsController < API::ApiController
def update
authorize Event
res = EventService.update(@event, event_params.permit!, params[:edit_mode])
render json: { action: 'update', total: res.length, updated: res.select { |r| r[:status] }.length, details: res }, status: :ok, location: @event
render json: { action: 'update', total: res[:events].length, updated: res[:events].select { |r| r[:status] }.length, details: res },
status: :ok,
location: @event
end
def destroy

View File

@ -4,7 +4,6 @@
class API::TranslationsController < API::ApiController
before_action :set_locale
def show
translations = I18n.t params[:state]
if translations.class.name == String.name && translations.start_with?('translation missing')
@ -16,6 +15,8 @@ class API::TranslationsController < API::ApiController
end
end
private
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end

View File

@ -12,6 +12,7 @@ class ApplicationController < ActionController::Base
respond_to :html, :json
before_action :configure_permitted_parameters, if: :devise_controller?
around_action :switch_locale
# Globally rescue Authorization Errors in controller.
# Returning 403 Forbidden if permission is denied
@ -61,6 +62,13 @@ class ApplicationController < ActionController::Base
head 403
end
# Set the configured locale for each action (API call)
# @see https://guides.rubyonrails.org/i18n.html
def switch_locale(&action)
locale = params[:locale] || Rails.application.secrets.rails_locale
I18n.with_locale(locale, &action)
end
# @return [User]
# This is a placeholder for Devise's current_user.
# As Devise generate the method at runtime, IDEs autocomplete features will complain about 'method not found'

View File

@ -0,0 +1,11 @@
import apiClient from './api-client';
import { AxiosResponse } from 'axios';
import { EventTheme } from '../models/event-theme';
export default class EventThemeAPI {
async index (): Promise<Array<EventTheme>> {
const res: AxiosResponse<Array<EventTheme>> = await apiClient.get(`/api/event_themes`);
return res?.data;
}
}

View File

@ -0,0 +1,11 @@
import apiClient from './api-client';
import { AxiosResponse } from 'axios';
import { Theme } from '../models/theme';
export default class ThemeAPI {
async index (): Promise<Array<Theme>> {
const res: AxiosResponse<Array<Theme>> = await apiClient.get(`/api/themes`);
return res?.data;
}
}

View File

@ -0,0 +1,102 @@
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import Select from 'react-select';
import { react2angular } from 'react2angular';
import { Loader } from './loader';
import { Event } from '../models/event';
import { EventTheme } from '../models/event-theme';
import { IApplication } from '../models/application';
import EventThemeAPI from '../api/event-theme';
declare var Application: IApplication;
interface EventThemesProps {
event: Event,
onChange: (themes: Array<EventTheme>) => void
}
/**
* Option format, expected by react-select
* @see https://github.com/JedWatson/react-select
*/
type selectOption = { value: number, label: string };
/**
* This component shows a select input to edit the themes associated with the event
*/
const EventThemes: React.FC<EventThemesProps> = ({ event, onChange }) => {
const { t } = useTranslation('shared');
const [themes, setThemes] = useState<Array<EventTheme>>([]);
useEffect(() => {
new EventThemeAPI().index().then(data => setThemes(data));
}, []);
/**
* Check if there's any EventTheme in DB, otherwise we won't display the selector
*/
const hasThemes = (): boolean => {
return themes.length > 0;
};
/**
* Return the current theme(s) for the given event, formatted to match the react-select format
*/
const defaultValues = (): Array<selectOption> => {
const res = [];
themes.forEach(t => {
if (event.event_theme_ids.indexOf(t.id) > -1) {
res.push({ value: t.id, label: t.name });
}
});
return res;
}
/**
* Callback triggered when the selection has changed.
* Convert the react-select specific format to an array of EventTheme, and call the provided callback.
*/
const handleChange = (selectedOptions: Array<selectOption>): void => {
const res = [];
selectedOptions.forEach(opt => {
res.push(themes.find(t => t.id === opt.value));
})
onChange(res);
}
/**
* Convert all themes to the react-select format
*/
const buildOptions = (): Array<selectOption> => {
return themes.map(t => {
return { value: t.id, label: t.name }
});
}
return (
<div className="event-themes">
{hasThemes() && <div className="event-themes--panel">
<h3>{ t('app.shared.event.event_themes') }</h3>
<div className="content">
<Select defaultValue={defaultValues()}
placeholder={t('app.shared.event.select_theme')}
onChange={handleChange}
options={buildOptions()}
isMulti />
</div>
</div>}
</div>
);
}
const EventThemesWrapper: React.FC<EventThemesProps> = ({ event, onChange }) => {
return (
<Loader>
<EventThemes event={event} onChange={onChange}/>
</Loader>
);
}
Application.Components.component('eventThemes', react2angular(EventThemesWrapper, ['event', 'onChange']));

View File

@ -21,6 +21,7 @@
*
* Provides :
* - $scope.datePicker = {}
* - $scope.event_themes = []
* - $scope.submited(content)
* - $scope.cancel()
* - $scope.addFile()
@ -31,9 +32,11 @@
* - $scope.toggleRecurrenceEnd(e)
* - $scope.addPrice()
* - $scope.removePrice(price, $event)
* - $scope.handleEventChange(?)
*
* Requires :
* - $scope.event.event_files_attributes = []
* - $scope.event.
* - $state (Ui-Router) [ 'app.public.events_list' ]
*/
class EventsController {
@ -49,6 +52,9 @@ class EventsController {
}
};
// themes of the current event
$scope.event_themes = $scope.event.event_theme_ids;
/**
* For use with ngUpload (https://github.com/twilson63/ngUpload).
* Intended to be the callback when an upload is done: any raised error will be stacked in the
@ -147,6 +153,14 @@ class EventsController {
$scope.event.prices.splice(index, 1);
}
};
/**
* When the theme selection has changes, extract the IDs to populate the form
* @param themes {Array<EventTheme>}
*/
$scope.handleEventChange = function (themes) {
$scope.event_themes = themes.map(t => t.id);
};
}
}
@ -284,7 +298,8 @@ Application.Controllers.controller('AdminEventsController', ['$scope', '$state',
resolve: {
category () { return {}; }
},
controller: 'PriceCategoryController' }).result['finally'](null).then(function (p_cat) {
controller: 'PriceCategoryController'
}).result.finally(null).then(function (p_cat) {
// save the price category to the API
PriceCategory.save(p_cat, function (cat) {
$scope.priceCategories.push(cat);
@ -312,7 +327,8 @@ Application.Controllers.controller('AdminEventsController', ['$scope', '$state',
resolve: {
category () { return $scope.priceCategories[index]; }
},
controller: 'PriceCategoryController' }).result['finally'](null).then(function (p_cat) {
controller: 'PriceCategoryController'
}).result.finally(null).then(function (p_cat) {
// update the price category to the API
PriceCategory.update({ id }, { price_category: p_cat }, function (cat) {
$scope.priceCategories[index] = cat;
@ -374,7 +390,6 @@ Application.Controllers.controller('AdminEventsController', ['$scope', '$state',
return $scope.page = 1;
};
/**
* Setup the feature-tour for the admin/events page.
* This is intended as a contextual help (when pressing F1)
@ -468,7 +483,7 @@ Application.Controllers.controller('AdminEventsController', ['$scope', '$state',
if (settingsPromise.feature_tour_display !== 'manual' && $scope.currentUser.profile.tours.indexOf('events') < 0) {
uitour.start();
}
}
};
/* PRIVATE SCOPE */
@ -532,9 +547,9 @@ Application.Controllers.controller('ShowEventReservationsController', ['$scope',
* @param reservation {Reservation}
* @returns {boolean}
*/
$scope.isCancelled = function(reservation) {
$scope.isCancelled = function (reservation) {
return !!(reservation.slots[0].canceled_at);
}
};
}]);
/**
@ -585,7 +600,7 @@ Application.Controllers.controller('NewEventController', ['$scope', '$state', 'C
];
// triggered when the new event form was submitted to the API and have received an answer
$scope.onSubmited = function(content) {
$scope.onSubmited = function (content) {
if ((content.id == null)) {
$scope.alerts = [];
angular.forEach(content, function (v, k) {
@ -655,7 +670,7 @@ Application.Controllers.controller('EditEventController', ['$scope', '$state', '
}
});
// submit form event by edit-mode
modalInstance.result.then(function(res) {
modalInstance.result.then(function (res) {
$scope.isShowEditModeModal = false;
$scope.editMode = res.editMode;
e.target.click();
@ -664,12 +679,12 @@ Application.Controllers.controller('EditEventController', ['$scope', '$state', '
};
// triggered when the edit event form was submitted to the API and have received an answer
$scope.onSubmited = function(data) {
$scope.onSubmited = function (data) {
if (data.total === data.updated) {
if (data.updated > 1) {
growl.success(_t(
'app.admin.events_edit.events_updated',
{COUNT: data.updated - 1}
{ COUNT: data.updated - 1 }
));
} else {
growl.success(_t(
@ -680,7 +695,7 @@ Application.Controllers.controller('EditEventController', ['$scope', '$state', '
if (data.total > 1) {
growl.warning(_t(
'app.admin.events_edit.events_not_updated',
{TOTAL: data.total, COUNT: data.total - data.updated}
{ TOTAL: data.total, COUNT: data.total - data.updated }
));
if (_.find(data.details, { error: 'EventPriceCategory' })) {
growl.error(_t(
@ -750,20 +765,20 @@ Application.Controllers.controller('EditRecurrentEventController', ['$scope', '$
$uibModalInstance.close({
editMode: $scope.editMode
});
}
};
/**
* Test if any of the dates of the event has changed
*/
$scope.hasDateChanged = function() {
$scope.hasDateChanged = function () {
return (!moment(initialDates.start).isSame(currentEvent.start_date, 'day') || !moment(initialDates.end).isSame(currentEvent.end_date, 'day'));
}
};
/**
* Cancellation callback
*/
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
}
};
}
]);

View File

@ -0,0 +1,11 @@
'use strict';
Application.Controllers.controller('HeaderController', ['$scope', '$rootScope', '$state',
function ($scope, $rootScope, $state) {
$scope.aboutPage = ($state.current.name === 'app.public.about');
$rootScope.$on('$stateChangeStart', function (event, toState) {
$scope.aboutPage = (toState.name === 'app.public.about');
});
}
]);

View File

@ -0,0 +1,5 @@
export interface EventTheme {
id: number,
name: string,
related_to: number
}

View File

@ -0,0 +1,50 @@
export interface Event {
id: number,
title: string,
description: string,
event_image: string,
event_files_attributes: Array<{
id: number,
attachment: string,
attachment_url: string
}>,
category_id: number,
category: {
id: number,
name: string,
slug: string
},
event_theme_ids: Array<number>,
event_themes: Array<{
name: string
}>,
age_range_id: number,
age_range: {
name: string
},
start_date: Date,
start_time: Date,
end_date: Date,
end_time: Date,
month: string;
month_id: number,
year: number,
all_day: boolean,
availability: {
id: number,
start_at: Date,
end_at: Date
},
availability_id: number,
amount: number,
prices: Array<{
id: number,
amount: number,
category: {
id: number,
name: string
}
}>,
nb_total_places: number,
nb_free_places: number
}

View File

@ -0,0 +1,4 @@
export interface Theme {
id: number,
name: string
}

View File

@ -21,7 +21,8 @@ angular.module('application.router', ['ui.router'])
abstract: true,
views: {
header: {
templateUrl: '/shared/header.html.erb'
templateUrl: '/shared/header.html.erb',
controller: 'HeaderController'
},
leftnav: {
templateUrl: '/shared/leftnav.html',

View File

@ -445,11 +445,12 @@
font-size: rem-calc(18);
}
p {
.about-title,
.about-title p
{
font-size: rem-calc(18);
line-height: rem-calc(30);
color: $black-light;
text-align: justify;
text-align: left;
}
&.ng-hide {

View File

@ -10,7 +10,8 @@
}
.about-fablab {
.about-title {
.about-title,
.about-title p {
font-size: rem-calc(30);
line-height: rem-calc(28);
text-align: center;

View File

@ -458,6 +458,10 @@ p, .widget p {
.p-l {
padding: 16px;
}
.p-h-0 {
padding-left: 0;
padding-right: 0;
}
.p-h-xs {
padding-left: 5px;

View File

@ -33,5 +33,6 @@
@import "modules/stripe-confirm";
@import "modules/payment-schedule-dashboard";
@import "modules/plan-card";
@import "modules/event-themes";
@import "app.responsive";

View File

@ -0,0 +1,20 @@
.event-themes {
&--panel {
border: 1px solid #dddddd;
border-radius: 6px;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
margin: 30px 15px;
h3 {
padding: 15px 15px;
border-bottom: 1px solid #dddddd;
margin: 0;
font-size: 1.4rem;
}
.content {
font-size: 1.4rem;
padding: 15px;
}
}
}

View File

@ -89,7 +89,7 @@
</p>
<div class="col-md-5">
<div class="input-group">
<input type="number" class="form-control" ng-model="availability.slot_duration" step="5" min="1" required="true" />
<input type="number" class="form-control" ng-model="availability.slot_duration" min="1" required="true" />
<span class="input-group-addon" translate>{{ 'app.admin.calendar.minutes' }}</span>
</div>
</div>

View File

@ -109,23 +109,9 @@
</div>
</div>
<div class="widget panel b-a m m-t-lg" ng-show="themes.length > 0">
<div class="panel-heading b-b small">
<h3 translate>{{ 'app.shared.event.event_theme' }}</h3>
</div>
<div class="widget-content no-bg wrapper">
<input type="hidden" name="event[event_theme_ids][]" value="" />
<ui-select ng-model="event.event_theme_ids" name="event[event_theme_ids][]">
<ui-select-match>
<span ng-bind="$select.selected.name"></span>
<input type="hidden" name="event[event_theme_ids][]" value="{{$select.selected.id}}" />
</ui-select-match>
<ui-select-choices repeat="t.id as t in (themes | filter: $select.search)">
<span ng-bind-html="t.name | highlight: $select.search"></span>
</ui-select-choices>
</ui-select>
</div>
</div>
<event-themes event="event" on-change="handleEventChange"></event-themes>
<input type="hidden" name="event[event_theme_ids][]" ng-repeat="id in event_themes" value="{{id}}" />
<input type="hidden" name="event[event_theme_ids][]" value="" ng-if="event_themes.length === 0" />
<div class="widget panel b-a m m-t-lg" ng-show="ageRanges.length > 0">
<div class="panel-heading b-b small">
@ -243,7 +229,7 @@
<div class="widget-content no-bg wrapper">
<div class="form-group">
<label for="event_amount" class="col-sm-5 control-label" translate>{{ 'app.shared.event.standard_rate' }}</label>
<div class="col-sm-5">
<div class="col-sm-6 p-h-0">
<div class="input-group">
<input ng-model="event.amount" type="number" name="event[amount]" class="form-control" id="event_amount" required>
<div class="input-group-addon">{{currencySymbol}}</div>
@ -260,7 +246,7 @@
ng-options="cat as cat.name for cat in priceCategories track by cat.id">
</select>
</div>
<div class="col-sm-5">
<div class="col-sm-6 p-h-0">
<div class="input-group">
<input ng-model="price.amount"
type="number"
@ -271,17 +257,17 @@
</div>
<div class="col-sm-1">
<input type="hidden" name="event[event_price_categories_attributes][][_destroy]" ng-value="price._destroy">
<a class="btn" ng-click="removePrice(price, $event)" href="#"><i class="fa fa-times text-danger"></i></a>
<a class="btn p-h-0" ng-click="removePrice(price, $event)" href="#"><i class="fa fa-times text-danger"></i></a>
</div>
</div>
<div class="link-icon m-b" ng-hide="event.prices.length == priceCategories.length">
<div class="col-sm-offset-5">
<i class="fa fa-plus"></i> <span ng-click="addPrice()">Ajouter un tarif</span>
<i class="fa fa-plus"></i> <span ng-click="addPrice()" translate>{{ 'app.shared.event.add_price' }}</span>
</div>
</div>
<div class="form-group">
<label for="event_nb_total_places" class="col-sm-5 control-label" translate>{{ 'app.shared.event.tickets_available' }}</label>
<div class="col-sm-6">
<div class="col-sm-6 p-h-0">
<div class="input-group">
<input ng-model="event.nb_total_places" type="number" name="event[nb_total_places]" class="form-control" id="event_nb_total_places">
<div class="input-group-addon"><i class="fa fa-ticket"></i> </div>

View File

@ -59,7 +59,9 @@
<h6 class="m-n" ng-if="event.amount">{{ 'app.public.events_list.full_price_' | translate }} {{event.amount | currency}} <span ng-repeat="price in event.prices">/ {{ price.category.name }} {{price.amount | currency}}</span></h6>
<div>
<span class="text-black-light text-xs" ng-if="event.event_themes[0]"><i class="fa fa-tags" aria-hidden="true"></i> {{event.event_themes[0].name}}</span>
<span class="text-black-light text-xs m-r-xs" ng-repeat="theme in event.event_themes">
<i class="fa fa-tags" aria-hidden="true"></i> {{theme.name}}
</span>
<span class="text-black-light text-xs" ng-if="event.age_range"><i class="fa fa-users" aria-hidden="true"></i> {{event.age_range.name}}</span>
</div>

View File

@ -75,7 +75,9 @@
<h5>{{event.category.name}}</h5>
<dl class="text-sm">
<dt ng-if="event.event_themes.length > 0"><i class="fa fa-tags" aria-hidden="true"></i> {{event.event_themes[0].name}}</dt>
<dt ng-repeat="theme in event.event_themes">
<i class="fa fa-tags" aria-hidden="true"></i> {{theme.name}}
</dt>
<dt ng-if="event.age_range"><i class="fa fa-users" aria-hidden="true"></i> {{event.age_range.name}}</dt>
</dl>
<dl class="text-sm">

View File

@ -1,7 +1,12 @@
<div class="navbar-header">
<a ng-click="toggleNavSize($event)" class="btn btn-link visible-xs" data-toggle="class:nav-off-screen" data-target="#nav"><i class="fa fa-bars"></i></a>
<a ui-sref="app.public.home" class="navbar-brand" ng-click="goabout = false">
<a ng-click="toggleNavSize($event)" class="btn btn-link visible-xs" data-toggle="class:nav-off-screen" data-target="#nav" ng-hide="aboutPage">
<i class="fa fa-bars"></i>
</a>
<a ui-sref="app.public.home" class="btn btn-link visible-xs" ng-show="aboutPage">
<i class="fa fa-caret-up"></i>
</a>
<a ui-sref="app.public.home" class="navbar-brand">
<img ng-src="{{logo.custom_asset_file_attributes.attachment_url}}" alt="{{logo.custom_asset_file_attributes.attachment}}" class="m-r-sm"/>
<%= "<label class='label-staging label label-warning text-sm hidden-sm hidden-xs'>Staging</label>".html_safe if Rails.env.staging? %>
</a>
@ -9,12 +14,12 @@
<ul class="nav navbar-nav hidden-xs">
<li class="about-page-link">
<a href class="about-link font-sbold text-sm" ng-click="goabout = !goabout" ui-sref="app.public.about" ng-show="!goabout">
<a href class="about-link font-sbold text-sm" ui-sref="app.public.about" ng-show="!aboutPage">
<span class="label label-theme rounded text-lg text-white m-r-sm font-ebold">?</span>
{{ linkName }}
</a>
<a href class="about-link font-sbold text-sm" ng-click="goabout = !goabout" ui-sref="app.public.home" ng-show="goabout">
<span class="label label-theme label-icon rounded text-lg text-white m-r-sm font-ebold"><i class="fa fa-caret-up" ng-show="goabout"></i></span>
<a href class="about-link font-sbold text-sm" ui-sref="app.public.home" ng-show="aboutPage">
<span class="label label-theme label-icon rounded text-lg text-white m-r-sm font-ebold"><i class="fa fa-caret-up" ng-show="aboutPage"></i></span>
{{ 'app.public.common.return' | translate }}
</a>
</li>

View File

@ -62,6 +62,11 @@
</a>
</li>
<!-- Common menu entries -->
<li class="hidden-sm hidden-md hidden-lg">
<a class="auto pointer" ui-sref="app.public.about">
<i class="fa fa-question-circle-o"></i> <span>{{ linkName }}</span>
</a>
</li>
<li class="{{navLink.class}}" ng-repeat="navLink in navLinks">
<a ng-click="toggleNavSize($event)" ui-sref="{{navLink.state}}" ui-sref-active="active" class="auto" data-toggle="class:nav-off-screen" data-target="#nav" ng-if="navLink.state">
<i class="fa fa-{{navLink.linkIcon}} fa-lg"></i>

View File

@ -135,7 +135,8 @@ class Invoice < PaymentDocument
def prevent_refund?
return true if user.nil?
if invoiced_type == 'Reservation' && invoiced.reservable_type == 'Training'
# workaround for reservation saved after invoice
if invoiced_type == 'Reservation' && invoiced&.reservable_type == 'Training'
user.trainings.include?(invoiced.reservable_id)
else
false

View File

@ -12,7 +12,7 @@ class Profile < ApplicationRecord
validates :last_name, presence: true, length: { maximum: 30 }
validates_numericality_of :phone, only_integer: true, allow_blank: false, if: -> { Setting.get('phone_required') }
after_commit :update_invoicing_profile, if: :invoicing_data_was_modified?, on: [:update]
after_commit :update_invoicing_profile, if: :invoicing_data_was_modified?
def full_name
# if first_name or last_name is nil, the empty string will be used as a temporary replacement

View File

@ -29,7 +29,7 @@ class ProjectUser < ApplicationRecord
def notify_project_author_when_collaborator_valid
NotificationCenter.call type: 'notify_project_author_when_collaborator_valid',
receiver: project.author,
receiver: project.author.user,
attached_object: self
end
end

View File

@ -438,7 +438,9 @@ class User < ApplicationRecord
raise NoProfileError if invoicing_profile.nil?
invoicing_profile.update_attributes(
email: email
email: email,
first_name: first_name,
last_name: last_name
)
end
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -353,7 +353,7 @@ class PDF::Invoice < Prawn::Document
transparent(0.1) do
rotate(45, origin: [0, 0]) do
image "#{Rails.root}/app/pdfs/data/watermark-#{I18n.locale}.png", at: [90, 150]
image "#{Rails.root}/app/pdfs/data/watermark-#{I18n.default_locale}.png", at: [90, 150]
end
end
end

View File

@ -126,7 +126,7 @@ class PDF::PaymentSchedule < Prawn::Document
transparent(0.1) do
rotate(45, origin: [0, 0]) do
image "#{Rails.root}/app/pdfs/data/watermark-#{I18n.locale}.png", at: [90, 150]
image "#{Rails.root}/app/pdfs/data/watermark-#{I18n.default_locale}.png", at: [90, 150]
end
end
end

View File

@ -102,7 +102,10 @@ class EventService
private
def update_events(event, events, event_params)
results = []
results = {
events: [],
slots: []
}
events.each do |e|
next unless e.id != event.id
@ -164,18 +167,18 @@ class EventService
event_files_attributes: ef_attributes
)
begin
results.push status: !!e.update(e_params.permit!), event: e # rubocop:disable Style/DoubleNegation
results[:events].push status: !!e.update(e_params.permit!), event: e # rubocop:disable Style/DoubleNegation
rescue StandardError => err
results.push status: false, event: e, error: err.try(:record).try(:class).try(:name), message: err.message
results[:events].push status: false, event: e, error: err.try(:record).try(:class).try(:name), message: err.message
end
results.concat(update_slots(e.availability_id))
results[:slots].concat(update_slots(e.availability_id))
end
begin
results.push status: !!event.update(event_params), event: event # rubocop:disable Style/DoubleNegation
results[:events].push status: !!event.update(event_params), event: event # rubocop:disable Style/DoubleNegation
rescue StandardError => err
results.push status: false, event: event, error: err.try(:record).try(:class).try(:name), message: err.message
results[:events].push status: false, event: event, error: err.try(:record).try(:class).try(:name), message: err.message
end
results.concat(update_slots(event.availability_id))
results[:slots].concat(update_slots(event.availability_id))
results
end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
json.extract! event, :id, :title, :description, :age_range_id
json.extract! event, :id, :title, :description
json.event_image event.event_image.attachment_url if event.event_image
json.event_files_attributes event.event_files do |f|
json.id f.id

View File

@ -1,7 +1,9 @@
# frozen_string_literal: true
json.title notification.notification_type
amount = notification.attached_object.amount
json.description t('.wallet_is_credited',
AMOUNT: number_to_currency(amount),
USER: notification.attached_object.wallet.user&.profile&.full_name || t('api.notifications.deleted_user'),
ADMIN: notification.attached_object.user&.profile&.full_name || t('api.notifications.deleted_user'))
AMOUNT: number_to_currency(amount),
USER: notification.attached_object.wallet.user&.profile&.full_name || t('api.notifications.deleted_user'),
ADMIN: notification.attached_object.user&.profile&.full_name || t('api.notifications.deleted_user'))

View File

@ -28,5 +28,7 @@ class OpenlabWorker
end
logger.debug ['Openlab sync', 'RESPONSE ERROR', response.inspect] unless response.success?
rescue Errno::ECONNREFUSED => e
logger.warn "Unable to connect to OpenProject, maybe the dev instance is not running: #{e}" if Rails.env.development?
end
end

View File

@ -40,9 +40,6 @@ module Fablab
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
config.time_zone = Rails.application.secrets.time_zone
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
config.to_prepare do
Devise::Mailer.layout 'notifications_mailer'
end
@ -66,6 +63,10 @@ module Fablab
# enable the app to find locales in plugins locales directory
config.i18n.load_path += Dir["#{Rails.root}/plugins/*/config/locales/*.yml"]
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true
# enable the app to find views in plugins views directory
Dir["#{Rails.root}/plugins/*/views"].each do |path|
Rails.application.config.paths['app/views'] << path

View File

@ -86,10 +86,6 @@ Rails.application.configure do
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
# config.action_mailer.raise_delivery_errors = false
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify

View File

@ -57,10 +57,6 @@ Rails.application.configure do
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
# config.action_mailer.raise_delivery_errors = false
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify

View File

@ -2,7 +2,7 @@
# List of all allowed values for RAILS_LOCALE
I18n.config.available_locales += %i[de de-AT de-CH de-DE
en en-AU-CA en-GB en-IE en-IN en-NZ en-US en-ZA
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
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
pt pt-BR
@ -14,5 +14,5 @@ I18n.config.available_locales += %i[de de-AT de-CH de-DE
#
# /!\ ALL locales SHOULD be configured accordingly with the default_locale. /!\
#
I18n.config.default_locale = Rails.application.secrets.rails_locale
I18n.config.default_locale = Rails.application.secrets.rails_locale.to_s.split('-')[0]
I18n.config.locale = Rails.application.secrets.rails_locale

View File

@ -157,8 +157,10 @@ de:
standard_rate: "Standardpreis"
0_equal_free: "0 = kostenlos"
tickets_available: "Tickets verfügbar"
event_theme: "Veranstaltungsthema"
event_themes: "Veranstaltungsthemen"
select_theme: "Pick up a theme..."
age_range: "Altersklasse"
add_price: "Add a price"
#subscription plan edition form
plan:
general_information: "Allgemeine Informationen"

View File

@ -157,8 +157,10 @@ en:
standard_rate: "Standard rate"
0_equal_free: "0 = free"
tickets_available: "Tickets available"
event_theme: "Event theme"
event_themes: "Event themes"
select_theme: "Pick up a theme..."
age_range: "Age range"
add_price: "Add a price"
#subscription plan edition form
plan:
general_information: "General information"

View File

@ -157,8 +157,10 @@ es:
standard_rate: "Puntuación estándar"
0_equal_free: "0 = Gratis"
tickets_available: "Entradas disponibles"
event_theme: "Tema del evento"
event_themes: "Temas del evento"
select_theme: "Pick up a theme..."
age_range: "Rango de edades"
add_price: "Add a price"
#subscription plan edition form
plan:
general_information: "Información general"

View File

@ -157,8 +157,10 @@ fr:
standard_rate: "Tarif standard"
0_equal_free: "0 = gratuit"
tickets_available: "Places disponibles"
event_theme: "Thème de l'événement"
event_themes: "Thèmes de l'événement"
select_theme: "Choisissez un thème ..."
age_range: "Tranche d'âge"
add_price: "Ajouter un tarif"
#subscription plan edition form
plan:
general_information: "Informations générales"

View File

@ -157,8 +157,10 @@ pt:
standard_rate: "Taxa padrão"
0_equal_free: "0 = grátis"
tickets_available: "Tickets disponíveis"
event_theme: "Tema do evento"
event_themes: "Temas do evento"
select_theme: "Pick up a theme..."
age_range: "Faixa etária"
add_price: "Add a price"
#subscription plan edition form
plan:
general_information: "Informação geral"

View File

@ -157,8 +157,10 @@ zu:
standard_rate: "crwdns9627:0crwdne9627:0"
0_equal_free: "crwdns9629:0crwdne9629:0"
tickets_available: "crwdns9631:0crwdne9631:0"
event_theme: "crwdns9633:0crwdne9633:0"
event_themes: "crwdns21464:0crwdne21464:0"
select_theme: "crwdns21466:0crwdne21466:0"
age_range: "crwdns9635:0crwdne9635:0"
add_price: "crwdns21468:0crwdne21468:0"
#subscription plan edition form
plan:
general_information: "crwdns9637:0crwdne9637:0"

View File

@ -0,0 +1,5 @@
de:
time:
formats:
# See http://apidock.com/ruby/DateTime/strftime for a list of available directives
hour_minute: "%I:%M %p"

View File

@ -77,6 +77,9 @@ You will also need to translate the invoice watermark, located in `app/pdfs/data
You'll find there the [GIMP source of the image](app/pdfs/data/watermark.xcf), which is using [Rubik Mono One](https://fonts.google.com/specimen/Rubik+Mono+One) as font.
Use it to generate a similar localised PNG image which keep the default image size, as PDF are not responsive.
Also, please create a [base.LOCALE.yml](../config/locales/base.en.yml) and fill it with the time-only format in use in your locale.
Finally, add your new locale and its derivatives to the `available_locales` array in [initializers/locale.rb](../config/initializers/locale.rb) to make it available in Fab-manager.
<a name="configuration"></a>
## Configuration

View File

@ -187,5 +187,13 @@ namespace :fablab do
end
end
end
desc '[release 4.7.9] fix invoicing profiles without names'
task invoices_without_names: :environment do
InvoicingProfile.where('(first_name IS NULL OR last_name IS NULL) AND user_id IS NOT NULL').each do |ip|
ip.update_attribute('first_name', ip.user.profile.first_name)
ip.update_attribute('last_name', ip.user.profile.last_name)
end
end
end
end

View File

@ -1,6 +1,6 @@
{
"name": "fab-manager",
"version": "4.7.8",
"version": "4.7.9",
"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",
@ -79,7 +79,7 @@
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
"bootstrap-sass": "3.4.1",
"checklist-model": "0.2",
"codemirror": "^4.8.0",
"codemirror": "^5.58.2",
"d3": "3.5",
"elasticsearch-browser": "3.1",
"fullcalendar": "3.10.2",
@ -102,13 +102,14 @@
"react-dom": "^17.0.0",
"react-i18next": "^11.7.3",
"react-modal": "^3.11.2",
"react-select": "^4.3.1",
"react-switch": "^5.0.1",
"react2angular": "^4.0.6",
"summernote": "0.8.18",
"twitter-fetcher": "^18.0.2",
"typescript": "^4.0.5",
"ui-select": "0.19",
"underscore": "1.7"
"underscore": "1.12"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0",

17
scripts/run.sh Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/env bash
yq() {
docker run --rm -i -v "${PWD}:/workdir" mikefarah/yq:4 "$@"
}
config() {
SERVICE="$(yq eval '.services.*.image | select(. == "sleede/fab-manager*") | path | .[-2]' docker-compose.yml)"
}
run()
{
config
docker-compose exec "$SERVICE" bundle exec rails "${@:-c}"
}
run "$@"

206
yarn.lock
View File

@ -970,10 +970,10 @@
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.12.0", "@babel/runtime@^7.3.1":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.1.tgz#b4116a6b6711d010b2dad3b7b6e43bf1b9954740"
integrity sha512-J5AIf3vPj3UwXaAzb5j1xM4WAQDX3EMgemF8rjCP3SoW09LfRKAXQKt6CoVYl230P6iWdRcBbnLDDdnqWxZSCA==
"@babel/runtime@^7.12.0", "@babel/runtime@^7.13.10", "@babel/runtime@^7.13.6", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
version "7.14.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.0.tgz#46794bc20b612c5f75e62dd071e24dfd95f1cbe6"
integrity sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==
dependencies:
regenerator-runtime "^0.13.4"
@ -1043,6 +1043,71 @@
resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7"
integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==
"@emotion/cache@^11.4.0":
version "11.4.0"
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.4.0.tgz#293fc9d9a7a38b9aad8e9337e5014366c3b09ac0"
integrity sha512-Zx70bjE7LErRO9OaZrhf22Qye1y4F7iDl+ITjet0J+i+B88PrAOBkKvaAWhxsZf72tDLajwCgfCjJ2dvH77C3g==
dependencies:
"@emotion/memoize" "^0.7.4"
"@emotion/sheet" "^1.0.0"
"@emotion/utils" "^1.0.0"
"@emotion/weak-memoize" "^0.2.5"
stylis "^4.0.3"
"@emotion/hash@^0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
"@emotion/memoize@^0.7.4":
version "0.7.5"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50"
integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==
"@emotion/react@^11.1.1":
version "11.4.0"
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.4.0.tgz#2465ad7b073a691409b88dfd96dc17097ddad9b7"
integrity sha512-4XklWsl9BdtatLoJpSjusXhpKv9YVteYKh9hPKP1Sxl+mswEFoUe0WtmtWjxEjkA51DQ2QRMCNOvKcSlCQ7ivg==
dependencies:
"@babel/runtime" "^7.13.10"
"@emotion/cache" "^11.4.0"
"@emotion/serialize" "^1.0.2"
"@emotion/sheet" "^1.0.1"
"@emotion/utils" "^1.0.0"
"@emotion/weak-memoize" "^0.2.5"
hoist-non-react-statics "^3.3.1"
"@emotion/serialize@^1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.2.tgz#77cb21a0571c9f68eb66087754a65fa97bfcd965"
integrity sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A==
dependencies:
"@emotion/hash" "^0.8.0"
"@emotion/memoize" "^0.7.4"
"@emotion/unitless" "^0.7.5"
"@emotion/utils" "^1.0.0"
csstype "^3.0.2"
"@emotion/sheet@^1.0.0", "@emotion/sheet@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.0.1.tgz#245f54abb02dfd82326e28689f34c27aa9b2a698"
integrity sha512-GbIvVMe4U+Zc+929N1V7nW6YYJtidj31lidSmdYcWozwoBIObXBnaJkKNDjZrLm9Nc0BR+ZyHNaRZxqNZbof5g==
"@emotion/unitless@^0.7.5":
version "0.7.5"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
"@emotion/utils@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.0.0.tgz#abe06a83160b10570816c913990245813a2fd6af"
integrity sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==
"@emotion/weak-memoize@^0.2.5":
version "0.2.5"
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46"
integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==
"@fortawesome/fontawesome-free@5.14.0":
version "5.14.0"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.14.0.tgz#a371e91029ebf265015e64f81bfbf7d228c9681f"
@ -2553,10 +2618,10 @@ code-point-at@^1.0.0:
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
codemirror@^4.8.0:
version "4.13.0"
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-4.13.0.tgz#209772d38a7bb99647c37b500db121110dd9af6f"
integrity sha1-IJdy04p7uZZHw3tQDbEhEQ3Zr28=
codemirror@^5.58.2:
version "5.58.2"
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.58.2.tgz#ed54a1796de1498688bea1cdd4e9eeb187565d1b"
integrity sha512-K/hOh24cCwRutd1Mk3uLtjWzNISOkm4fvXiMO7LucCrqbh6aJDdtqUziim3MZUI6wOY0rvY1SlL1Ork01uMy6w==
collection-visit@^1.0.0:
version "1.0.0"
@ -3301,6 +3366,14 @@ doctrine@^3.0.0:
dependencies:
esutils "^2.0.2"
dom-helpers@^5.0.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902"
integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==
dependencies:
"@babel/runtime" "^7.8.7"
csstype "^3.0.2"
dom-serializer@0:
version "0.2.2"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51"
@ -4569,6 +4642,13 @@ hmac-drbg@^1.0.1:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
hoist-non-react-statics@^3.3.1:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
dependencies:
react-is "^16.7.0"
holderjs@2.6:
version "2.6.0"
resolved "https://registry.yarnpkg.com/holderjs/-/holderjs-2.6.0.tgz#e2ab6e02d4177684c0fe1414ecea013bc4b1505e"
@ -4587,9 +4667,9 @@ hone@1.1.0:
integrity sha512-OT6AXfa+pMwM0jJbpyZk6/pgQ4m9vMkiUSKMfRbYv+Tnca/IRLsfBbmJy/FcsrqujW54Yvn6g+ApBwUnD8MQZg==
hosted-git-info@^2.1.4:
version "2.8.8"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488"
integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==
version "2.8.9"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
hpack.js@^2.1.6:
version "2.1.6"
@ -4654,12 +4734,12 @@ html-minifier-terser@^5.1.1:
relateurl "^0.2.7"
terser "^4.6.3"
html-parse-stringify2@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/html-parse-stringify2/-/html-parse-stringify2-2.0.1.tgz#dc5670b7292ca158b7bc916c9a6735ac8872834a"
integrity sha1-3FZwtyksoVi3vJFsmmc1rIhyg0o=
html-parse-stringify@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2"
integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==
dependencies:
void-elements "^2.0.1"
void-elements "3.1.0"
htmlparser2@^4.1.0:
version "4.1.0"
@ -4761,9 +4841,9 @@ i18next-icu@^1.4.2:
intl-messageformat "2.2.0"
i18next@^19.8.3:
version "19.8.3"
resolved "https://registry.yarnpkg.com/i18next/-/i18next-19.8.3.tgz#10df7222db8c23389b13bceb9ba67a5e20a0241e"
integrity sha512-eVrqAw2gGGYYJaJMYw4VM1FNFawLD4b84IsoTZMVXeWHaxAM2gyTa34j2Sip15UkBz/LrSxdFJj0Jhlrz7EvHA==
version "19.9.2"
resolved "https://registry.yarnpkg.com/i18next/-/i18next-19.9.2.tgz#ea5a124416e3c5ab85fddca2c8e3c3669a8da397"
integrity sha512-0i6cuo6ER6usEOtKajUUDj92zlG+KArFia0857xxiEHAQcUwh/RtOQocui1LPJwunSYT574Pk64aNva1kwtxZg==
dependencies:
"@babel/runtime" "^7.12.0"
@ -5642,21 +5722,11 @@ lodash.uniq@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
lodash@^4.0.0, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.5, lodash@~4.17.10:
lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10, lodash@~4.17.20:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
lodash@^4.17.11, lodash@^4.17.4, lodash@~4.17.20:
version "4.17.20"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
lodash@^4.17.14:
version "4.17.19"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
loglevel@^1.6.8:
version "1.7.0"
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.0.tgz#728166855a740d59d38db01cf46f042caa041bb0"
@ -5774,6 +5844,11 @@ medium-editor@4.4.0:
resolved "https://registry.yarnpkg.com/medium-editor/-/medium-editor-4.4.0.tgz#ef188cc9cc5cba87177da8cb657a885dfbbe5760"
integrity sha1-7xiMycxcuocXfajLZXqIXfu+V2A=
memoize-one@^5.0.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
memory-fs@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
@ -7558,7 +7633,7 @@ promise-inflight@^1.0.1:
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2:
prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@ -7728,14 +7803,21 @@ react-dom@^17.0.0:
scheduler "^0.20.0"
react-i18next@^11.7.3:
version "11.7.3"
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.7.3.tgz#256461c46baf5b3208c3c6860ca4e569fc7ed053"
integrity sha512-7sYZqVZgdaS9Z0ZH6nuJFErCD0zz5wK3jR4/xCrWjZcxHHF3GRu7BXdicbSPprZV4ZYz7LJzxxMHO7dg5Qb70A==
version "11.8.15"
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.8.15.tgz#89450d585298f18d4a8eb1628b0868863f3a4767"
integrity sha512-ZbKcbYYKukgDL0MiUWKJTEsEftjSTNVZv67/V+SjPqTRwuF/aL4NbUtuEcb4WjHk0HyZ1M+2wGd07Fp0RUNHKA==
dependencies:
"@babel/runtime" "^7.3.1"
html-parse-stringify2 "2.0.1"
"@babel/runtime" "^7.13.6"
html-parse-stringify "^3.0.1"
react-is@^16.8.1:
react-input-autosize@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-3.0.0.tgz#6b5898c790d4478d69420b55441fcc31d5c50a85"
integrity sha512-nL9uS7jEs/zu8sqwFE5MAPx6pPkNAriACQ2rGLlqmKr2sPGtN7TXTyDdQt4lbNXVx7Uzadb40x8qotIuru6Rhg==
dependencies:
prop-types "^15.5.8"
react-is@^16.7.0, react-is@^16.8.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
@ -7760,6 +7842,19 @@ react-refresh@^0.9.0:
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.9.0.tgz#71863337adc3e5c2f8a6bfddd12ae3bfe32aafbf"
integrity sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==
react-select@^4.3.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/react-select/-/react-select-4.3.1.tgz#389fc07c9bc7cf7d3c377b7a05ea18cd7399cb81"
integrity sha512-HBBd0dYwkF5aZk1zP81Wx5UsLIIT2lSvAY2JiJo199LjoLHoivjn9//KsmvQMEFGNhe58xyuOITjfxKCcGc62Q==
dependencies:
"@babel/runtime" "^7.12.0"
"@emotion/cache" "^11.4.0"
"@emotion/react" "^11.1.1"
memoize-one "^5.0.0"
prop-types "^15.6.0"
react-input-autosize "^3.0.0"
react-transition-group "^4.3.0"
react-switch@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/react-switch/-/react-switch-5.0.1.tgz#449277f4c3aed5286fffd0f50d5cbc2a23330406"
@ -7767,6 +7862,16 @@ react-switch@^5.0.1:
dependencies:
prop-types "^15.6.2"
react-transition-group@^4.3.0:
version "4.4.1"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9"
integrity sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==
dependencies:
"@babel/runtime" "^7.5.5"
dom-helpers "^5.0.1"
loose-envify "^1.4.0"
prop-types "^15.6.2"
react2angular@^4.0.6:
version "4.0.6"
resolved "https://registry.yarnpkg.com/react2angular/-/react2angular-4.0.6.tgz#ec49ef834d101c9a320e25229fc5afa5b29edc4f"
@ -8889,6 +8994,11 @@ stylehacks@^4.0.0:
postcss "^7.0.0"
postcss-selector-parser "^3.0.0"
stylis@^4.0.3:
version "4.0.10"
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.10.tgz#446512d1097197ab3f02fb3c258358c3f7a14240"
integrity sha512-m3k+dk7QeJw660eIKRRn3xPF6uuvHs/FFzjX3HQ5ove0qYsiygoAhwn5a3IYKaZPo5LrYD0rfVmtv1gNY1uYwg==
summernote@0.8.18:
version "0.8.18"
resolved "https://registry.yarnpkg.com/summernote/-/summernote-0.8.18.tgz#be5c368b1c92de8a05039a9976157bdea7aae386"
@ -9241,10 +9351,10 @@ unbox-primitive@^1.0.0:
has-symbols "^1.0.2"
which-boxed-primitive "^1.0.2"
underscore@1.7:
version "1.7.0"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209"
integrity sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=
underscore@1.12:
version "1.12.1"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.12.1.tgz#7bb8cc9b3d397e201cf8553336d262544ead829e"
integrity sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==
unicode-canonical-property-names-ecmascript@^1.0.4:
version "1.0.4"
@ -9339,9 +9449,9 @@ urix@^0.1.0:
integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
url-parse@^1.4.3:
version "1.4.7"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278"
integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==
version "1.5.1"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.1.tgz#d5fa9890af8a5e1f274a2c98376510f6425f6e3b"
integrity sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==
dependencies:
querystringify "^2.1.1"
requires-port "^1.0.0"
@ -9445,10 +9555,10 @@ vm-browserify@^1.0.1:
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
void-elements@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=
void-elements@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09"
integrity sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=
warning@^4.0.3:
version "4.0.3"