diff --git a/CHANGELOG.md b/CHANGELOG.md index 609b5691c..a4b90e33d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,31 @@ # Changelog Fab-manager +- The upgrade script will check and report the ability to access the hub API +- Fix a bug: the upgrade script report an invalid version to upgrade to +- Fix a security issue: updated tar to 6.1.11 to fix [CVE-2021-37712](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37712), [CVE-2021-37701](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37701) and [CVE-2021-37713](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37713) +- Fix a security issue: updated immer to 9.0.6 to fix [CVE-2021-3757](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3757) and [CVE-2021-23436](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-23436) +- Fix a security issue: updated url-parse to 1.5.3 to fix [CVE-2021-3664](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3664) +- Fix a security issue: updated axios to 0.21.2 to fix [CVE-2021-3749](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3749) +- Fix a security issue: updated nokogiri to 1.12.5 to fix [CVE-2021-41098](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41098) + +## v5.1.10 2021 October 04 + +- Fix a bug: the image of the about page is not using the image set in backoffice +- Fix a bug: updated sassc to 2.4.0 to fix ruby runtime error on some CPU architectures (#270) +- Fix a security issue: prevent HTML code edition in projects, to prevent XSS vulnerability (#293) + +## v5.1.9 2021 September 21 + +- Add a setting for the purchase and use of a prepaid pack is only possible for the user with a valid subscription +- Fix a bug: unable to show plan name in calendar reservations +- Fix a bug: book overlapping slot setting label name + ## v5.1.8 2021 September 13 - Improved stripe 3D secure payment on payment schedules - Disable monthly payment for the subscription with interval 1 month - Fix a bug: unable to show statistics module in nav menu after login -- Fix a bug: plans page show an error if admin dont create any plans +- Fix a bug: plans page show an error if admin don't create any plans ## v5.1.7 2021 August 24 @@ -14,12 +34,12 @@ ## v5.1.6 2021 August 6 -- Adjuste packs pricing popover position +- Adjust packs pricing popover position - Updated Norwegian language - Updated addressable from 2.7.0 to 2.8.0 - Updated tar from 6.1.0 to 6.1.4 - Fix a bug: unable to generate avoir of wallet -- Fix a bug: manager cant reserve training for user +- Fix a bug: managers can't reserve trainings for users ## v5.1.5 2021 August 2 @@ -60,6 +80,22 @@ - [TODO DEPLOY] `rails db:seed` - [TODO DEPLOY] `rails fablab:maintenance:rebuild_stylesheet` +## v5.0.14 2021 September 30 + +- Fix a bug: unable to show plan name in calendar reservations +- Fix a bug: book overlapping slot setting labal name + +## v5.0.13 2021 September 13 + +- Improved stripe 3D secure payment on payment schedules +- Disable monthly payment for the subscription with interval 1 month +- Fix a bug: unable to show statistics module in nav menu after login +- Fix a bug: plans page show an error if admin dont create any plans + +## v5.0.12 2021 August 24 + +- Fix a bug: unable to show plans page + ## v5.0.11 2021 August 6 - Fix a bug: unable to generate avoir of wallet diff --git a/Gemfile.lock b/Gemfile.lock index 00d4392af..ec42603fb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -140,7 +140,7 @@ GEM i18n (>= 1.6, < 2) faraday (0.17.3) multipart-post (>= 1.2, < 3) - ffi (1.15.1) + ffi (1.15.4) foreman (0.87.0) forgery (0.7.0) friendly_id (5.1.0) @@ -205,7 +205,7 @@ GEM rake mini_magick (4.10.1) mini_mime (1.1.0) - mini_portile2 (2.5.1) + mini_portile2 (2.6.1) minitest (5.14.4) minitest-reporters (1.4.2) ansi @@ -217,8 +217,8 @@ GEM multi_xml (0.6.0) multipart-post (2.1.1) nio4r (2.5.7) - nokogiri (1.11.4) - mini_portile2 (~> 2.5.0) + nokogiri (1.12.5) + mini_portile2 (~> 2.6.1) racc (~> 1.4) notify_with (0.0.2) jbuilder (~> 2.0) @@ -341,7 +341,7 @@ GEM rubyzip (>= 1.3.0) rubyzip (2.3.0) safe_yaml (1.0.5) - sassc (2.2.1) + sassc (2.4.0) ffi (~> 1.9) seed_dump (3.3.1) activerecord (>= 4) diff --git a/app/frontend/src/javascript/components/machines/reserve-button.tsx b/app/frontend/src/javascript/components/machines/reserve-button.tsx index 606a37b93..5c8869112 100644 --- a/app/frontend/src/javascript/components/machines/reserve-button.tsx +++ b/app/frontend/src/javascript/components/machines/reserve-button.tsx @@ -9,6 +9,8 @@ import MachineAPI from '../../api/machine'; import { Machine } from '../../models/machine'; import { User } from '../../models/user'; import { IApplication } from '../../models/application'; +import SettingAPI from '../../api/setting'; +import { SettingName } from '../../models/setting'; declare const Application: IApplication; @@ -36,11 +38,17 @@ const ReserveButtonComponent: React.FC = ({ currentUser, mac const [pendingTraining, setPendingTraining] = useState(false); const [trainingRequired, setTrainingRequired] = useState(false); const [proposePacks, setProposePacks] = useState(false); + const [isPackOnlyForSubscription, setIsPackOnlyForSubscription] = useState(true); // handle login from an external process useEffect(() => setUser(currentUser), [currentUser]); // check the trainings after we retrieved the machine data useEffect(() => checkTraining(), [machine]); + useEffect(() => { + SettingAPI.get(SettingName.PackOnlyForSubscription) + .then(data => setIsPackOnlyForSubscription(data.value === 'true')) + .catch(error => onError(error)); + }, []); /** * Callback triggered when the user clicks on the 'reserve' button. @@ -136,8 +144,9 @@ const ReserveButtonComponent: React.FC = ({ currentUser, mac */ const checkPrepaidPack = (): void => { // if the customer has already bought a pack or if there's no active packs for this machine, + // or customer has not any subscription if admin active pack only for subscription option // let the customer reserve - if (machine.current_user_has_packs || !machine.has_prepaid_packs_for_current_user) { + if (machine.current_user_has_packs || !machine.has_prepaid_packs_for_current_user || (isPackOnlyForSubscription && !currentUser.subscribed_plan)) { return onReserveMachine(machine); } diff --git a/app/frontend/src/javascript/components/prepaid-packs/packs-summary.tsx b/app/frontend/src/javascript/components/prepaid-packs/packs-summary.tsx index 94a4d23f0..4e455444b 100644 --- a/app/frontend/src/javascript/components/prepaid-packs/packs-summary.tsx +++ b/app/frontend/src/javascript/components/prepaid-packs/packs-summary.tsx @@ -36,11 +36,15 @@ const PacksSummaryComponent: React.FC = ({ item, itemType, cu const [userPacks, setUserPacks] = useState>(null); const [threshold, setThreshold] = useState(null); const [packsModal, setPacksModal] = useState(false); + const [isPackOnlyForSubscription, setIsPackOnlyForSubscription] = useState(true); useEffect(() => { SettingAPI.get(SettingName.RenewPackThreshold) .then(data => setThreshold(parseFloat(data.value))) .catch(error => onError(error)); + SettingAPI.get(SettingName.PackOnlyForSubscription) + .then(data => setIsPackOnlyForSubscription(data.value === 'true')) + .catch(error => onError(error)); }, []); useEffect(() => { @@ -127,13 +131,32 @@ const PacksSummaryComponent: React.FC = ({ item, itemType, cu if (_.isEmpty(customer)) return
; // prevent component rendering if ths customer have no packs and there are no packs available if (totalHours() === 0 && packs?.length === 0) return
; + // render remaining hours and a warning if customer has not any subscription if admin active pack only for subscription option + if (totalHours() > 0) { + return ( +
+

{t('app.logged.packs_summary.prepaid_hours')}

+
+ + {t('app.logged.packs_summary.remaining_HOURS', { HOURS: totalHours(), ITEM: itemType })} + {isPackOnlyForSubscription && !customer.subscribed_plan && +
+ {t('app.logged.packs_summary.unable_to_use_pack_for_subsription_is_expired')} +
+ } +
+
+
+ ); + } + // prevent component rendering buy pack button if customer has not any subscription if admin active pack only for subscription option + if (isPackOnlyForSubscription && !customer.subscribed_plan) return
; return (

{t('app.logged.packs_summary.prepaid_hours')}

- {totalHours() > 0 && t('app.logged.packs_summary.remaining_HOURS', { HOURS: totalHours(), ITEM: itemType })} {totalHours() === 0 && t('app.logged.packs_summary.no_hours', { ITEM: itemType })} {shouldDisplayButton() &&
diff --git a/app/frontend/src/javascript/controllers/admin/calendar.js b/app/frontend/src/javascript/controllers/admin/calendar.js index 659c778c5..49928ac7d 100644 --- a/app/frontend/src/javascript/controllers/admin/calendar.js +++ b/app/frontend/src/javascript/controllers/admin/calendar.js @@ -956,14 +956,14 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui }); $scope.tagsName = localizedList(tags); if ($scope.isOnlySubscriptions && $scope.selectedPlans.length > 0) { - $scope.plansName = localizedList($scope.selectedPlans); + $scope.plansName = localizedList($scope.selectedPlans, 'base_name'); } }; - const localizedList = function (items) { + const localizedList = function (items, attr = 'name') { if (items.length === 0) return `${_t('app.admin.calendar.none')}`; - const names = items.map(function (i) { return $sce.trustAsHtml(`${i.name}`); }); + const names = items.map(function (i) { return $sce.trustAsHtml(`${i[attr]}`); }); if (items.length > 1) return names.slice(0, -1).join(', ') + ` ${_t('app.admin.calendar.and')} ` + names[names.length - 1]; return names[0]; diff --git a/app/frontend/src/javascript/controllers/projects.js b/app/frontend/src/javascript/controllers/projects.js index afb313737..46bb5ab7d 100644 --- a/app/frontend/src/javascript/controllers/projects.js +++ b/app/frontend/src/javascript/controllers/projects.js @@ -22,6 +22,7 @@ * in the various projects' admin controllers. * * Provides : + * - $scope.summernoteOptsProject * - $scope.totalSteps * - $scope.machines = [{Machine}] * - $scope.components = [{Component}] @@ -42,7 +43,11 @@ * - $state (Ui-Router) [ 'app.public.projects_show', 'app.public.projects_list' ] */ class ProjectsController { - constructor ($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, Diacritics, dialogs, allowedExtensions, _t) { + constructor ($rootScope, $scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, Diacritics, dialogs, allowedExtensions, _t) { + // remove codeview from summernote editor + $scope.summernoteOptsProject = angular.copy($rootScope.summernoteOpts); + $scope.summernoteOptsProject.toolbar[6][1].splice(1, 1); + // Retrieve the list of machines from the server Machine.query().$promise.then(function (data) { $scope.machines = data.map(function (d) { @@ -449,8 +454,8 @@ Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'P /** * Controller used in the project creation page */ -Application.Controllers.controller('NewProjectController', ['$scope', '$state', 'Project', 'Machine', 'Member', 'Component', 'Theme', 'Licence', '$document', 'CSRF', 'Diacritics', 'dialogs', 'allowedExtensions', '_t', - function ($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, CSRF, Diacritics, dialogs, allowedExtensions, _t) { +Application.Controllers.controller('NewProjectController', ['$rootScope', '$scope', '$state', 'Project', 'Machine', 'Member', 'Component', 'Theme', 'Licence', '$document', 'CSRF', 'Diacritics', 'dialogs', 'allowedExtensions', '_t', + function ($rootScope, $scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, CSRF, Diacritics, dialogs, allowedExtensions, _t) { CSRF.setMetaTags(); // API URL where the form will be posted @@ -468,7 +473,7 @@ Application.Controllers.controller('NewProjectController', ['$scope', '$state', $scope.matchingMembers = []; // Using the ProjectsController - return new ProjectsController($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, Diacritics, dialogs, allowedExtensions, _t); + return new ProjectsController($rootScope, $scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, Diacritics, dialogs, allowedExtensions, _t); } ]); @@ -509,7 +514,7 @@ Application.Controllers.controller('EditProjectController', ['$rootScope', '$sco } // Using the ProjectsController - return new ProjectsController($scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, Diacritics, dialogs, allowedExtensions, _t); + return new ProjectsController($rootScope, $scope, $state, Project, Machine, Member, Component, Theme, Licence, $document, Diacritics, dialogs, allowedExtensions, _t); }; // !!! MUST BE CALLED AT THE END of the controller diff --git a/app/frontend/src/javascript/filters/filters.js b/app/frontend/src/javascript/filters/filters.js index e6cb02e7c..466a5fb6a 100644 --- a/app/frontend/src/javascript/filters/filters.js +++ b/app/frontend/src/javascript/filters/filters.js @@ -166,7 +166,7 @@ Application.Filters.filter('simpleText', [function () { }]); Application.Filters.filter('toTrusted', ['$sce', function ($sce) { - return text => $sce.trustAsHtml(text); + return text => $sce.getTrustedHtml(text); }]); Application.Filters.filter('planIntervalFilter', [function () { diff --git a/app/frontend/src/javascript/models/setting.ts b/app/frontend/src/javascript/models/setting.ts index 3e5031a03..439f211c5 100644 --- a/app/frontend/src/javascript/models/setting.ts +++ b/app/frontend/src/javascript/models/setting.ts @@ -110,6 +110,7 @@ export enum SettingName { PayZenCurrency = 'payzen_currency', PublicAgendaModule = 'public_agenda_module', RenewPackThreshold = 'renew_pack_threshold', + PackOnlyForSubscription = 'pack_only_for_subscription', } export type SettingValue = string|boolean|number; diff --git a/app/frontend/src/javascript/router.js b/app/frontend/src/javascript/router.js index 70fa98b8e..cad2f9a5b 100644 --- a/app/frontend/src/javascript/router.js +++ b/app/frontend/src/javascript/router.js @@ -1080,7 +1080,7 @@ angular.module('application.router', ['ui.router']) "'reminder_delay', 'visibility_yearly', 'visibility_others', 'wallet_module', 'trainings_module', " + "'display_name_enable', 'machines_sort_by', 'fab_analytics', 'statistics_module', 'address_required', " + "'link_name', 'home_content', 'home_css', 'phone_required', 'upcoming_events_shown', 'public_agenda_module'," + - "'renew_pack_threshold']" + "'renew_pack_threshold', 'pack_only_for_subscription']" }).$promise; }], privacyDraftsPromise: ['Setting', function (Setting) { return Setting.get({ name: 'privacy_draft', history: true }).$promise; }], diff --git a/app/frontend/templates/admin/calendar/calendar.html b/app/frontend/templates/admin/calendar/calendar.html index b15596f49..591ec09bc 100644 --- a/app/frontend/templates/admin/calendar/calendar.html +++ b/app/frontend/templates/admin/calendar/calendar.html @@ -115,7 +115,7 @@
{{::g.name}}
  • - {{::plan.name}} + {{::plan.base_name}}
diff --git a/app/frontend/templates/admin/calendar/eventModal.html b/app/frontend/templates/admin/calendar/eventModal.html index 9eb65ee64..d148ec256 100644 --- a/app/frontend/templates/admin/calendar/eventModal.html +++ b/app/frontend/templates/admin/calendar/eventModal.html @@ -149,7 +149,7 @@
{{::group.name}}
diff --git a/app/frontend/templates/admin/settings/reservations.html b/app/frontend/templates/admin/settings/reservations.html index ad2a10ec1..ee40a9f81 100644 --- a/app/frontend/templates/admin/settings/reservations.html +++ b/app/frontend/templates/admin/settings/reservations.html @@ -87,7 +87,7 @@

{{ 'app.admin.settings.book_overlapping_slots_info' }}

@@ -169,5 +169,14 @@ step="0.01">
+
+

{{ 'app.admin.settings.pack_only_for_subscription_info' }}

+

+ + +
diff --git a/app/frontend/templates/machines/_form.html b/app/frontend/templates/machines/_form.html index 47ae75cf2..76cf91140 100644 --- a/app/frontend/templates/machines/_form.html +++ b/app/frontend/templates/machines/_form.html @@ -49,7 +49,7 @@ required bs-jasny-fileinput> - {{ 'app.shared.buttons.delete' }} +
diff --git a/app/frontend/templates/projects/_form.html b/app/frontend/templates/projects/_form.html index 029ad7deb..c4b643f64 100644 --- a/app/frontend/templates/projects/_form.html +++ b/app/frontend/templates/projects/_form.html @@ -71,7 +71,7 @@
- + {{ 'app.shared.project.description_is_required' }}
diff --git a/app/frontend/templates/shared/_cart.html b/app/frontend/templates/shared/_cart.html index 3e48a4363..93ad2aa57 100644 --- a/app/frontend/templates/shared/_cart.html +++ b/app/frontend/templates/shared/_cart.html @@ -37,7 +37,7 @@
{{::group.name}}
    -
  • {{::plan.name}}
  • +
  • {{::plan.base_name}}
diff --git a/app/frontend/templates/shared/_reserve_slot_without_plan.html b/app/frontend/templates/shared/_reserve_slot_without_plan.html index 671c26fb7..2d815322c 100644 --- a/app/frontend/templates/shared/_reserve_slot_without_plan.html +++ b/app/frontend/templates/shared/_reserve_slot_without_plan.html @@ -11,7 +11,7 @@
{{::group.name}}
    -
  • {{::plan.name}}
  • +
  • {{::plan.base_name}}
diff --git a/app/models/cart_item/subscription.rb b/app/models/cart_item/subscription.rb index 4b1a96f17..d4ccd3e13 100644 --- a/app/models/cart_item/subscription.rb +++ b/app/models/cart_item/subscription.rb @@ -24,7 +24,7 @@ class CartItem::Subscription < CartItem::BaseItem end def name - @plan.name + @plan.base_name end def to_object diff --git a/app/models/plan.rb b/app/models/plan.rb index 562192ac6..18cae24c8 100644 --- a/app/models/plan.rb +++ b/app/models/plan.rb @@ -132,6 +132,6 @@ class Plan < ApplicationRecord end def update_gateway_product - PaymentGatewayService.new.create_or_update_product(Plan.name, id) + PaymentGatewayService.new.create_or_update_product(Plan.base_name, id) end end diff --git a/app/models/setting.rb b/app/models/setting.rb index 8deaafc5a..aee06ebae 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -119,7 +119,8 @@ class Setting < ApplicationRecord payzen_hmac payzen_currency public_agenda_module - renew_pack_threshold] } + renew_pack_threshold + pack_only_for_subscription] } # WARNING: when adding a new key, you may also want to add it in app/policies/setting_policy.rb#public_whitelist def value diff --git a/app/models/subscription.rb b/app/models/subscription.rb index 413f9b273..980c94b4b 100644 --- a/app/models/subscription.rb +++ b/app/models/subscription.rb @@ -57,7 +57,7 @@ class Subscription < ApplicationRecord operator_profile_id: operator_profile_id, total: 0 ) - invoice.invoice_items.push InvoiceItem.new(amount: 0, description: plan.name, object: od) + invoice.invoice_items.push InvoiceItem.new(amount: 0, description: plan.base_name, object: od) invoice.save if save diff --git a/app/policies/setting_policy.rb b/app/policies/setting_policy.rb index 472a8206a..e9496a6f8 100644 --- a/app/policies/setting_policy.rb +++ b/app/policies/setting_policy.rb @@ -39,7 +39,8 @@ class SettingPolicy < ApplicationPolicy tracking_id book_overlapping_slots slot_duration events_in_calendar spaces_module plans_module invoicing_module recaptcha_site_key feature_tour_display disqus_shortname allowed_cad_extensions openlab_app_id openlab_default online_payment_module stripe_public_key confirmation_required wallet_module trainings_module address_required - payment_gateway payzen_endpoint payzen_public_key public_agenda_module renew_pack_threshold statistics_module] + payment_gateway payzen_endpoint payzen_public_key public_agenda_module renew_pack_threshold statistics_module + pack_only_for_subscription] end ## diff --git a/app/services/invoices_service.rb b/app/services/invoices_service.rb index 055fa7fd8..bed591f4b 100644 --- a/app/services/invoices_service.rb +++ b/app/services/invoices_service.rb @@ -175,7 +175,7 @@ class InvoicesService invoice.invoice_items.push InvoiceItem.new( amount: payment_details[:elements][:plan], - description: subscription.plan.name, + description: subscription.plan.base_name, object: subscription, main: main ) diff --git a/app/services/payment_schedule_service.rb b/app/services/payment_schedule_service.rb index 978f06f4e..c626b1a95 100644 --- a/app/services/payment_schedule_service.rb +++ b/app/services/payment_schedule_service.rb @@ -249,7 +249,7 @@ class PaymentScheduleService invoice.invoice_items.push InvoiceItem.new( amount: payment_details[:subscription], - description: subscription.plan.name, + description: subscription.plan.base_name, object: subscription, main: main ) diff --git a/app/services/prepaid_pack_service.rb b/app/services/prepaid_pack_service.rb index 14149a047..58ba51d8a 100644 --- a/app/services/prepaid_pack_service.rb +++ b/app/services/prepaid_pack_service.rb @@ -61,6 +61,11 @@ class PrepaidPackService ## Total number of prepaid minutes available def minutes_available(user, priceable) + is_pack_only_for_subscription = Setting.find_by(name: "pack_only_for_subscription")&.value + if is_pack_only_for_subscription == 'true' && !user.subscribed_plan + return 0 + end + user_packs = user_packs(user, priceable) total_available = user_packs.map { |up| up.prepaid_pack.minutes }.reduce(:+) || 0 total_used = user_packs.map(&:minutes_used).reduce(:+) || 0 diff --git a/app/themes/casemate/style.scss.erb b/app/themes/casemate/style.scss.erb index cee1dcadf..ca75da0a8 100644 --- a/app/themes/casemate/style.scss.erb +++ b/app/themes/casemate/style.scss.erb @@ -279,9 +279,6 @@ a.label:focus, } .about-picture { - background: linear-gradient( rgba(255,255,255,0.12), rgba(255,255,255,0.13) ), - linear-gradient(<%=Stylesheet.primary_with_alpha(0.78)%>, <%=Stylesheet.primary_with_alpha(0.82)%>), - url('/about-fablab.jpg') no-repeat; } .social-icons > div:hover { @@ -289,7 +286,7 @@ a.label:focus, color: $secondary-text-color; } -.profile-top { +.profile-top, .about-picture { background: linear-gradient( rgba(255,255,255,0.12), rgba(255,255,255,0.13) ), linear-gradient(<%=Stylesheet.primary_with_alpha(0.78)%>, <%=Stylesheet.primary_with_alpha(0.82)%>), url("<%=CustomAsset.get_url('profile-image-file') || '/about-fablab.jpg'%>") no-repeat; diff --git a/app/views/api/members/index.json.jbuilder b/app/views/api/members/index.json.jbuilder index eefe34b94..a952955cc 100644 --- a/app/views/api/members/index.json.jbuilder +++ b/app/views/api/members/index.json.jbuilder @@ -57,6 +57,7 @@ json.array!(@members) do |member| json.plan do json.id member.subscription.plan.id json.name member.subscription.plan.name + json.base_name member.subscription.plan.base_name json.interval member.subscription.plan.interval json.amount member.subscription.plan.amount ? (member.subscription.plan.amount / 100.0) : 0 end diff --git a/app/views/api/notifications/_notify_admin_subscribed_plan.json.jbuilder b/app/views/api/notifications/_notify_admin_subscribed_plan.json.jbuilder index 0cdd145ec..f3b97bef5 100644 --- a/app/views/api/notifications/_notify_admin_subscribed_plan.json.jbuilder +++ b/app/views/api/notifications/_notify_admin_subscribed_plan.json.jbuilder @@ -1,5 +1,4 @@ json.title notification.notification_type json.description t('.subscription_PLAN_has_been_subscribed_by_USER_html', - PLAN: notification.attached_object.plan.name, + PLAN: notification.attached_object.plan.base_name, USER: notification.attached_object.user&.profile&.full_name || t('api.notifications.deleted_user')) - diff --git a/app/views/api/notifications/_notify_admin_subscription_extended.json.jbuilder b/app/views/api/notifications/_notify_admin_subscription_extended.json.jbuilder index 19dae0ab9..636b8b5ea 100644 --- a/app/views/api/notifications/_notify_admin_subscription_extended.json.jbuilder +++ b/app/views/api/notifications/_notify_admin_subscription_extended.json.jbuilder @@ -1,9 +1,8 @@ json.title notification.notification_type json.description _t('.subscription_PLAN_of_the_member_USER_has_been_extended_FREE_until_DATE_html', { - PLAN: notification.attached_object.plan.name, + PLAN: notification.attached_object.plan.base_name, USER: notification.attached_object.user&.profile&.full_name || t('api.notifications.deleted_user'), FREE: notification.get_meta_data(:free_days).to_s, DATE: I18n.l(notification.attached_object.expired_at.to_date) }) # messageFormat - diff --git a/app/views/api/notifications/_notify_member_subscribed_plan.json.jbuilder b/app/views/api/notifications/_notify_member_subscribed_plan.json.jbuilder index 359ed650c..a7dadea1b 100644 --- a/app/views/api/notifications/_notify_member_subscribed_plan.json.jbuilder +++ b/app/views/api/notifications/_notify_member_subscribed_plan.json.jbuilder @@ -1,4 +1,3 @@ json.title notification.notification_type json.description t('.you_have_subscribed_to_PLAN_html', - PLAN: notification.attached_object.plan.name) - + PLAN: notification.attached_object.plan.base_name) diff --git a/app/views/api/notifications/_notify_member_subscription_canceled.json.jbuilder b/app/views/api/notifications/_notify_member_subscription_canceled.json.jbuilder index 32b3caadd..f08da3099 100644 --- a/app/views/api/notifications/_notify_member_subscription_canceled.json.jbuilder +++ b/app/views/api/notifications/_notify_member_subscription_canceled.json.jbuilder @@ -1,4 +1,3 @@ json.title notification.notification_type json.description t('.your_subscription_PLAN_was_successfully_cancelled_html', - PLAN: notification.attached_object.plan.name) - + PLAN: notification.attached_object.plan.base_name) diff --git a/app/views/api/notifications/_notify_member_subscription_extended.json.jbuilder b/app/views/api/notifications/_notify_member_subscription_extended.json.jbuilder index 43c9fd2cc..6f650c58d 100644 --- a/app/views/api/notifications/_notify_member_subscription_extended.json.jbuilder +++ b/app/views/api/notifications/_notify_member_subscription_extended.json.jbuilder @@ -1,8 +1,7 @@ json.title notification.notification_type json.description _t('.your_subscription_PLAN_has_been_extended_FREE_until_DATE_html', { - PLAN: notification.attached_object.plan.name, + PLAN: notification.attached_object.plan.base_name, FREE: notification.get_meta_data(:free_days).to_s, DATE: I18n.l(notification.attached_object.expired_at.to_date) }) # messageFormat - diff --git a/app/views/api/notifications/_notify_partner_subscribed_plan.json.jbuilder b/app/views/api/notifications/_notify_partner_subscribed_plan.json.jbuilder index 985e15baf..067338c1d 100644 --- a/app/views/api/notifications/_notify_partner_subscribed_plan.json.jbuilder +++ b/app/views/api/notifications/_notify_partner_subscribed_plan.json.jbuilder @@ -1,7 +1,6 @@ json.title notification.notification_type json.description t('.subscription_partner_PLAN_has_been_subscribed_by_USER_html', { - PLAN: notification.attached_object.plan.name, + PLAN: notification.attached_object.plan.base_name, USER: notification.attached_object.user&.profile&.full_name || t('api.notifications.deleted_user') }) # messageFormat - diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index 309ddde02..93c05fd35 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -1154,7 +1154,7 @@ en: error_SETTING_locked: "Unable to update the setting: {SETTING} is locked. Please contact your system administrator." an_error_occurred_saving_the_setting: "An error occurred while saving the setting. Please try again later." book_overlapping_slots_info: "Allow / prevent the reservation of overlapping slots" - prevent_booking: "Prevent booking" + allow_booking: "Allow booking" default_slot_duration: "Default duration for slots" duration_minutes: "Duration (in minutes)" default_slot_duration_info: "Machine and space availabilities are divided in multiple slots of this duration. This value can be overridden per availability." @@ -1208,6 +1208,9 @@ en: display_invite_to_renew_pack: "Display the invite to renew prepaid-packs" packs_threshold_info_html: "You can define under how many hours the user will be invited to buy a new prepaid-pack, if his stock of prepaid hours is under this threshold.
You can set a number of hours (eg. 5) or a percentage of his current pack pack (eg. 0.05 means 5%)." renew_pack_threshold: "threshold for packs renewal" + pack_only_for_subscription_info_html: "If this option is activated, the purchase and use of a prepaid pack is only possible for the user with a valid subscription." + pack_only_for_subscription: "Subscription valid for purchase and use of a prepaid pack" + pack_only_for_subscription_info: "Make subscription mandatory for prepaid packs" general: general: "General" title: "Title" diff --git a/config/locales/app.logged.en.yml b/config/locales/app.logged.en.yml index df0c17c53..6f559be96 100644 --- a/config/locales/app.logged.en.yml +++ b/config/locales/app.logged.en.yml @@ -196,6 +196,7 @@ en: remaining_HOURS: "You have {HOURS} prepaid hours remaining for this {ITEM, select, Machine{machine} Space{space} other{}}." no_hours: "You don't have any prepaid hours for this {ITEM, select, Machine{machine} Space{space} other{}}." buy_a_new_pack: "Buy a new pack" + unable_to_use_pack_for_subsription_is_expired: "You must have a valid subscription to use your remaining hours." #book a training trainings_reserve: trainings_planning: "Trainings planning" diff --git a/db/seeds.rb b/db/seeds.rb index 2ba5dc126..d25f4e9d6 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -899,6 +899,8 @@ Setting.set('public_agenda_module', true) unless Setting.find_by(name: 'public_a Setting.set('renew_pack_threshold', 0.2) unless Setting.find_by(name: 'renew_pack_threshold').try(:value) +Setting.set('pack_only_for_subscription', true) unless Setting.find_by(name: 'pack_only_for_subscription').try(:value) + if StatisticCustomAggregation.count.zero? # available reservations hours for machines machine_hours = StatisticType.find_by(key: 'hour', statistic_index_id: 2) diff --git a/package.json b/package.json index ce32774a6..01b3d27ba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fab-manager", - "version": "5.1.8", + "version": "5.1.10", "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", @@ -83,7 +83,7 @@ "angular-ui-tour": "https://github.com/sleede/angular-ui-tour.git#master", "angular-unsavedchanges": "0.2", "angular-xeditable": "0.10", - "axios": "^0.21.1", + "axios": "^0.21.2", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", "bootstrap-sass": "3.4.1", "checklist-model": "0.2", @@ -95,7 +95,7 @@ "i18next": "^19.8.3", "i18next-http-backend": "^1.0.21", "i18next-icu": "^1.4.2", - "immer": "^9.0.1", + "immer": "^9.0.6", "jasny-bootstrap": "3.1", "jquery": ">=3.5.0", "jquery-ujs": "^1.2.2", diff --git a/setup/upgrade.sh b/setup/upgrade.sh index 1c9fb469d..c1676b191 100644 --- a/setup/upgrade.sh +++ b/setup/upgrade.sh @@ -89,6 +89,11 @@ target_version() if [[ "$TAG" =~ ^:release-v[\.0-9]+$ ]]; then TARGET=$(echo "$TAG" | grep -Eo '[\.0-9]{5}') elif [ "$TAG" = ":latest" ] || [ "$TAG" = "" ]; then + HTTP_CODE=$(curl -I -s -w "%{http_code}\n" -o /dev/null https://hub.fab-manager.com/api/versions/latest) + if [ "$HTTP_CODE" != 200 ]; then + printf "\n\n\e[91m[ ❌ ] Unable to retrieve the last version of Fab-manager. Please check your internet connection or restart this script providing the \e[1m-t\e[0m\e[91m option\n\e[39m" + exit 3 + fi TARGET=$(\curl -sSL "https://hub.fab-manager.com/api/versions/latest" | jq -r '.semver') else TARGET='custom' @@ -120,8 +125,8 @@ version_check() version_error "v4.0.4 first" elif verlt "$VERSION" 4.4.6 && verlt 4.4.6 "$TARGET"; then version_error "v4.4.6 first" - elif verlt "$VERSION" 4.7.13 && verlt 4.7.13 "$TARGET"; then - version_error "v4.7.13 first" + elif verlt "$VERSION" 4.7.14 && verlt 4.7.14 "$TARGET"; then + version_error "v4.7.14 first" elif verlt "$TARGET" "$VERSION"; then version_error "a version > $VERSION" fi diff --git a/yarn.lock b/yarn.lock index d8e831501..fa3cabe34 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1924,12 +1924,12 @@ autoprefixer@^9.6.1: postcss "^7.0.32" postcss-value-parser "^4.1.0" -axios@^0.21.1: - version "0.21.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" - integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== +axios@^0.21.2: + version "0.21.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.2.tgz#21297d5084b2aeeb422f5d38e7be4fbb82239017" + integrity sha512-87otirqUw3e8CzHTMO+/9kh/FSgXt/eVDvipijwDtEuwbkySWZ9SBm6VEubmJ/kLKEoLQV/POhxXFb66bfekfg== dependencies: - follow-redirects "^1.10.0" + follow-redirects "^1.14.0" babel-loader@^8.2.2: version "8.2.2" @@ -3962,10 +3962,10 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" -follow-redirects@^1.0.0, follow-redirects@^1.10.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43" - integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg== +follow-redirects@^1.0.0, follow-redirects@^1.14.0: + version "1.14.3" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.3.tgz#6ada78118d8d24caee595595accdc0ac6abd022e" + integrity sha512-3MkHxknWMUtb23apkgz/83fDoe+y+qr0TdgacGIA7bew+QLBo3vdgEN2xEsuXNivpFy4CyDhBBZnNZOtalmenw== for-in@^1.0.2: version "1.0.2" @@ -4507,10 +4507,10 @@ ignore@^5.1.1, ignore@^5.1.4: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== -immer@^9.0.1: - version "9.0.3" - resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.3.tgz#146e2ba8b84d4b1b15378143c2345559915097f4" - integrity sha512-mONgeNSMuyjIe0lkQPa9YhdmTv8P19IeHV0biYhcXhbd5dhdB9HSK93zBpyKjp6wersSUgT5QyU0skmejUVP2A== +immer@^9.0.6: + version "9.0.6" + resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.6.tgz#7a96bf2674d06c8143e327cbf73539388ddf1a73" + integrity sha512-G95ivKpy+EvVAnAab4fVa4YGYn24J1SpEktnJX7JJ45Bd7xqME/SCplFzYFmTbrkwZbQ4xJK1xMTUYBkN6pWsQ== import-cwd@^2.0.0: version "2.1.0" @@ -8197,9 +8197,9 @@ tapable@^1.0.0, tapable@^1.1.3: integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== tar@^6.0.2: - version "6.1.4" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.4.tgz#9f0722b772a5e00dba7d52e1923b37a7ec3799b3" - integrity sha512-kcPWrO8S5ABjuZ/v1xQHP8xCEvj1dQ1d9iAb6Qs4jLYzaAIYWwST2IQpz7Ud8VNYRI+fGhFjrnzRKmRggKWg3g== + version "6.1.11" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" + integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" @@ -8530,9 +8530,9 @@ urix@^0.1.0: integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= url-parse@^1.4.3, url-parse@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.1.tgz#d5fa9890af8a5e1f274a2c98376510f6425f6e3b" - integrity sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q== + version "1.5.3" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.3.tgz#71c1303d38fb6639ade183c2992c8cc0686df862" + integrity sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ== dependencies: querystringify "^2.1.1" requires-port "^1.0.0"