mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2024-12-01 12:24:28 +01:00
Merge branch 'dev' for release 5.4.4
This commit is contained in:
commit
3c3bab3b62
@ -42,6 +42,7 @@ Dockerfile
|
||||
docker-compose*
|
||||
test
|
||||
.env
|
||||
.docker
|
||||
|
||||
# Docs
|
||||
*.md
|
||||
|
14
CHANGELOG.md
14
CHANGELOG.md
@ -2,6 +2,20 @@
|
||||
|
||||
## next deploy
|
||||
|
||||
## v5.4.4 2022 June 8
|
||||
|
||||
- Check shopping cart items are valid before online payment
|
||||
- Updated sidekiq-unique-jobs to 7.1.23 to get rid of Sidekiq's default_worker_options deprecation warning
|
||||
- Allow moving with arrows in the setup script's inputs
|
||||
- Ability to ignore assets compilation errors in the upgrade script
|
||||
- Fix a bug: admins are shown in select member for reservation by admin
|
||||
- Fix a bug: unable to show tours in machines and spaces page
|
||||
- Fix a bug: unable to connect with OAuth2
|
||||
- Fix a bug: when installing fab-manager as non-root user, most of the resulting installation directories were owned by root
|
||||
- Fix a bug: unable to edit OIDC provider
|
||||
- Fix a bug: list of OIDC scopes are loading indefinitely
|
||||
- [TODO DEPLOY] `\curl -sSL https://raw.githubusercontent.com/sleede/fab-manager/master/scripts/use-relative-paths.sh | bash`
|
||||
|
||||
## v5.4.3 2022 June 6
|
||||
|
||||
- Updated translations
|
||||
|
27
Dockerfile
27
Dockerfile
@ -48,6 +48,11 @@ COPY Gemfile /tmp/
|
||||
COPY Gemfile.lock /tmp/
|
||||
RUN bundle config set --local without 'development test doc' && bundle install && bundle binstubs --all
|
||||
|
||||
# Prepare the application directories
|
||||
RUN mkdir -p /var/log/supervisor && \
|
||||
mkdir -p /usr/src/app/tmp/sockets && \
|
||||
mkdir -p /usr/src/app/tmp/pids
|
||||
|
||||
# Install Javascript packages
|
||||
WORKDIR /usr/src/app
|
||||
COPY package.json /usr/src/app/package.json
|
||||
@ -62,25 +67,11 @@ RUN apk del .build-deps && \
|
||||
/var/cache/apk/* \
|
||||
/usr/lib/ruby/gems/*/cache/*
|
||||
|
||||
# Web app
|
||||
RUN mkdir -p /usr/src/app && \
|
||||
mkdir -p /usr/src/app/config && \
|
||||
mkdir -p /usr/src/app/invoices && \
|
||||
mkdir -p /usr/src/app/payment_schedules && \
|
||||
mkdir -p /usr/src/app/exports && \
|
||||
mkdir -p /usr/src/app/imports && \
|
||||
mkdir -p /usr/src/app/log && \
|
||||
mkdir -p /usr/src/app/public/uploads && \
|
||||
mkdir -p /usr/src/app/public/packs && \
|
||||
mkdir -p /usr/src/app/accounting && \
|
||||
mkdir -p /usr/src/app/proof_of_identity_files && \
|
||||
mkdir -p /usr/src/app/tmp/sockets && \
|
||||
mkdir -p /usr/src/app/tmp/pids
|
||||
|
||||
# Copy source files
|
||||
COPY docker/database.yml /usr/src/app/config/database.yml
|
||||
COPY . /usr/src/app
|
||||
|
||||
# Volumes
|
||||
# Volumes (the folders are created by setup.sh)
|
||||
VOLUME /usr/src/app/invoices
|
||||
VOLUME /usr/src/app/payment_schedules
|
||||
VOLUME /usr/src/app/exports
|
||||
@ -97,5 +88,5 @@ EXPOSE 3000
|
||||
|
||||
# The main command to run when the container starts. Also tell the Rails server
|
||||
# to bind to all interfaces by default.
|
||||
COPY docker/supervisor.conf /etc/supervisor/conf.d/fablab.conf
|
||||
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/fablab.conf"]
|
||||
COPY docker/supervisor.conf /etc/supervisor/conf.d/fabmanager.conf
|
||||
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/fabmanager.conf"]
|
||||
|
2
Gemfile
2
Gemfile
@ -92,7 +92,7 @@ gem 'aasm'
|
||||
gem 'sidekiq', '>= 6.0.7'
|
||||
# Recurring jobs for Sidekiq
|
||||
gem 'sidekiq-scheduler'
|
||||
gem 'sidekiq-unique-jobs', '~> 7.1.15'
|
||||
gem 'sidekiq-unique-jobs', '~> 7.1.23'
|
||||
|
||||
gem 'stripe', '5.29.0'
|
||||
|
||||
|
@ -398,7 +398,7 @@ GEM
|
||||
rufus-scheduler (~> 3.2)
|
||||
sidekiq (>= 4)
|
||||
tilt (>= 1.4.0)
|
||||
sidekiq-unique-jobs (7.1.15)
|
||||
sidekiq-unique-jobs (7.1.23)
|
||||
brpoplpush-redis_script (> 0.1.1, <= 2.0.0)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.5)
|
||||
sidekiq (>= 5.0, < 8.0)
|
||||
@ -546,7 +546,7 @@ DEPENDENCIES
|
||||
shakapacker (= 6.2.0)
|
||||
sidekiq (>= 6.0.7)
|
||||
sidekiq-scheduler
|
||||
sidekiq-unique-jobs (~> 7.1.15)
|
||||
sidekiq-unique-jobs (~> 7.1.23)
|
||||
spring
|
||||
spring-watcher-listen (~> 2.0.0)
|
||||
stripe (= 5.29.0)
|
||||
|
2
Procfile
2
Procfile
@ -1,3 +1,3 @@
|
||||
web: bundle exec rails server puma -p $PORT
|
||||
#web: bundle exec rails server puma -p $PORT
|
||||
worker: bundle exec sidekiq -C ./config/sidekiq.yml
|
||||
webpack: bin/webpacker-dev-server
|
||||
|
@ -180,7 +180,7 @@ class API::MembersController < API::ApiController
|
||||
end
|
||||
|
||||
def search
|
||||
@members = Members::ListService.search(current_user, params[:query], params[:subscription])
|
||||
@members = Members::ListService.search(current_user, params[:query], params[:subscription], params[:project])
|
||||
end
|
||||
|
||||
def mapping
|
||||
|
@ -53,6 +53,14 @@ class API::PayzenController < API::PaymentsController
|
||||
render json: e, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
def check_cart
|
||||
cart = shopping_cart
|
||||
unless cart.valid?
|
||||
render json: { error: 'unable to pay' }, status: :unprocessable_entity and return
|
||||
end
|
||||
render json: { cart: 'ok' }, status: :ok
|
||||
end
|
||||
|
||||
def check_hash
|
||||
@result = PayZen::Helper.check_hash(params[:algorithm], params[:hash_key], params[:hash], params[:data])
|
||||
end
|
||||
|
@ -19,6 +19,9 @@ class API::StripeController < API::PaymentsController
|
||||
res = nil # json of the API answer
|
||||
|
||||
cart = shopping_cart
|
||||
unless cart.valid?
|
||||
render json: { error: 'unable to pay' }, status: :unprocessable_entity and return
|
||||
end
|
||||
begin
|
||||
amount = debit_amount(cart) # will contains the amount and the details of each invoice lines
|
||||
if params[:payment_method_id].present?
|
||||
@ -71,10 +74,7 @@ class API::StripeController < API::PaymentsController
|
||||
|
||||
def setup_subscription
|
||||
cart = shopping_cart
|
||||
cart.items.each do |item|
|
||||
raise InvalidSubscriptionError unless item.valid?(cart.items)
|
||||
raise InvalidSubscriptionError unless item.to_object.errors.empty?
|
||||
end
|
||||
raise InvalidSubscriptionError unless cart.valid?
|
||||
|
||||
service = Stripe::Service.new
|
||||
method = service.attach_method_as_default(
|
||||
|
@ -46,4 +46,9 @@ export default class PayzenAPI {
|
||||
const res: AxiosResponse<CreateTokenResponse> = await apiClient.post('/api/payzen/update_token', { payment_schedule_id: paymentScheduleId });
|
||||
return res?.data;
|
||||
}
|
||||
|
||||
static async checkCart (cart: ShoppingCart, customer: User): Promise<CreatePaymentResponse> {
|
||||
const res: AxiosResponse<CreatePaymentResponse> = await apiClient.post('/api/payzen/check_cart', { cart_items: cart, customer_id: customer.id });
|
||||
return res?.data;
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ export const OpenidConnectForm = <TFieldValues extends FieldValues, TContext ext
|
||||
const unlisted = difference(current, scopesAvailable);
|
||||
callback(scopesAvailable.concat(unlisted).map(scope => ({ value: scope, label: scope })));
|
||||
} else {
|
||||
current.map(scope => ({ value: scope, label: scope }));
|
||||
callback(current.map(scope => ({ value: scope, label: scope })));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -132,6 +132,7 @@ export const PayzenForm: React.FC<PayzenFormProps> = ({ onSubmit, onSuccess, onE
|
||||
try {
|
||||
const { result } = await PayZenKR.current.validateForm();
|
||||
if (result === null) {
|
||||
await PayzenAPI.checkCart(cart, customer);
|
||||
await PayZenKR.current.onSubmit(onPaid);
|
||||
await PayZenKR.current.onError(handleError);
|
||||
await PayZenKR.current.submit();
|
||||
|
@ -213,14 +213,14 @@ Application.Controllers.controller('MachinesController', ['$scope', '$state', '_
|
||||
});
|
||||
// on tour end, save the status in database
|
||||
uitour.on('ended', function () {
|
||||
if (uitour.getStatus() === uitour.Status.ON && $scope.currentUser.profile.tours.indexOf('machines') < 0) {
|
||||
if (uitour.getStatus() === uitour.Status.ON && $scope.currentUser.profile_attributes.tours.indexOf('machines') < 0) {
|
||||
Member.completeTour({ id: $scope.currentUser.id }, { tour: 'machines' }, function (res) {
|
||||
$scope.currentUser.profile.tours = res.tours;
|
||||
$scope.currentUser.profile_attributes.tours = res.tours;
|
||||
});
|
||||
}
|
||||
});
|
||||
// if the user has never seen the tour, show him now
|
||||
if (settingsPromise.feature_tour_display !== 'manual' && $scope.currentUser.profile.tours.indexOf('machines') < 0) {
|
||||
if (settingsPromise.feature_tour_display !== 'manual' && $scope.currentUser.profile_attributes.tours.indexOf('machines') < 0) {
|
||||
uitour.start();
|
||||
}
|
||||
}
|
||||
|
@ -231,7 +231,7 @@ class ProjectsController {
|
||||
const asciiName = Diacritics.remove(nameLookup);
|
||||
|
||||
Member.search(
|
||||
{ query: asciiName },
|
||||
{ query: asciiName, project: 'true' },
|
||||
function (users) { $scope.matchingMembers = users; },
|
||||
function (error) { console.error(error); }
|
||||
);
|
||||
|
@ -186,14 +186,14 @@ Application.Controllers.controller('SpacesController', ['$scope', '$state', 'spa
|
||||
});
|
||||
// on tour end, save the status in database
|
||||
uitour.on('ended', function () {
|
||||
if (uitour.getStatus() === uitour.Status.ON && $scope.currentUser.profile.tours.indexOf('spaces') < 0) {
|
||||
if (uitour.getStatus() === uitour.Status.ON && $scope.currentUser.profile_attributes.tours.indexOf('spaces') < 0) {
|
||||
Member.completeTour({ id: $scope.currentUser.id }, { tour: 'spaces' }, function (res) {
|
||||
$scope.currentUser.profile.tours = res.tours;
|
||||
$scope.currentUser.profile_attributes.tours = res.tours;
|
||||
});
|
||||
}
|
||||
});
|
||||
// if the user has never seen the tour, show him now
|
||||
if (settingsPromise.feature_tour_display !== 'manual' && $scope.currentUser.profile.tours.indexOf('spaces') < 0) {
|
||||
if (settingsPromise.feature_tour_display !== 'manual' && $scope.currentUser.profile_attributes.tours.indexOf('spaces') < 0) {
|
||||
uitour.start();
|
||||
}
|
||||
}
|
||||
|
@ -2,12 +2,14 @@
|
||||
|
||||
# A discount coupon applied to the whole shopping cart
|
||||
class CartItem::Coupon
|
||||
attr_reader :errors
|
||||
|
||||
# @param coupon {String|Coupon} may be nil or empty string if no coupons are applied
|
||||
def initialize(customer, operator, coupon)
|
||||
@customer = customer
|
||||
@operator = operator
|
||||
@coupon = coupon
|
||||
@errors = {}
|
||||
end
|
||||
|
||||
def coupon
|
||||
@ -27,4 +29,15 @@ class CartItem::Coupon
|
||||
def type
|
||||
'coupon'
|
||||
end
|
||||
|
||||
def valid?(_all_items)
|
||||
return true if @coupon.nil?
|
||||
|
||||
c = ::Coupon.find_by(code: @coupon)
|
||||
if c.nil? || c.status(@customer.id) != 'active'
|
||||
@errors[:item] = 'coupon is invalid'
|
||||
return false
|
||||
end
|
||||
true
|
||||
end
|
||||
end
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
# A payment schedule applied to plan in the shopping cart
|
||||
class CartItem::PaymentSchedule
|
||||
attr_reader :requested
|
||||
attr_reader :requested, :errors
|
||||
|
||||
def initialize(plan, coupon, requested, customer, start_at = nil)
|
||||
raise TypeError unless coupon.is_a? CartItem::Coupon
|
||||
@ -12,6 +12,7 @@ class CartItem::PaymentSchedule
|
||||
@requested = requested
|
||||
@customer = customer
|
||||
@start_at = start_at
|
||||
@errors = {}
|
||||
end
|
||||
|
||||
def schedule(total, total_without_coupon)
|
||||
@ -33,4 +34,12 @@ class CartItem::PaymentSchedule
|
||||
def type
|
||||
'subscription'
|
||||
end
|
||||
|
||||
def valid?(_all_items)
|
||||
if @plan&.disabled
|
||||
@errors[:item] = 'plan is disabled'
|
||||
return false
|
||||
end
|
||||
true
|
||||
end
|
||||
end
|
||||
|
@ -37,4 +37,12 @@ class CartItem::PrepaidPack < CartItem::BaseItem
|
||||
def type
|
||||
'pack'
|
||||
end
|
||||
|
||||
def valid?(_all_items)
|
||||
if @pack.disabled
|
||||
@errors[:item] = 'pack is disabled'
|
||||
return false
|
||||
end
|
||||
true
|
||||
end
|
||||
end
|
||||
|
@ -43,7 +43,26 @@ class CartItem::Reservation < CartItem::BaseItem
|
||||
def valid?(all_items)
|
||||
pending_subscription = all_items.find { |i| i.is_a?(CartItem::Subscription) }
|
||||
@slots.each do |slot|
|
||||
availability = Availability.find(slot[:availability_id])
|
||||
availability = Availability.find_by(id: slot[:availability_id])
|
||||
if availability.nil?
|
||||
@errors[:slot] = 'slot availability no exist'
|
||||
return false
|
||||
end
|
||||
|
||||
if availability.available_type == 'machines'
|
||||
s = Slot.find_by(start_at: slot[:start_at], end_at: slot[:end_at], availability_id: slot[:availability_id], canceled_at: nil)
|
||||
unless s.nil?
|
||||
@errors[:slot] = 'slot has reserved'
|
||||
return false
|
||||
end
|
||||
elsif availability.available_type == 'space' && availability.spaces.first.disabled.nil?
|
||||
@errors[:slot] = 'space is disabled'
|
||||
return false
|
||||
elsif availability.completed?
|
||||
@errors[:slot] = 'availability has completed'
|
||||
return false
|
||||
end
|
||||
|
||||
next if availability.plan_ids.empty?
|
||||
next if (@customer.subscribed_plan && availability.plan_ids.include?(@customer.subscribed_plan.id)) ||
|
||||
(pending_subscription && availability.plan_ids.include?(pending_subscription.plan.id)) ||
|
||||
|
@ -41,4 +41,12 @@ class CartItem::Subscription < CartItem::BaseItem
|
||||
def type
|
||||
'subscription'
|
||||
end
|
||||
|
||||
def valid?(_all_items)
|
||||
if @plan.disabled
|
||||
@errors[:item] = 'plan is disabled'
|
||||
return false
|
||||
end
|
||||
true
|
||||
end
|
||||
end
|
||||
|
@ -87,6 +87,19 @@ class ShoppingCart
|
||||
{ success: success, payment: payment, errors: errors }
|
||||
end
|
||||
|
||||
def valid?
|
||||
items.each do |item|
|
||||
next if item.valid?(@items)
|
||||
|
||||
return false
|
||||
end
|
||||
return false unless @coupon.valid?([])
|
||||
|
||||
return false unless @payment_schedule.valid?([])
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Save the object associated with the provided item or raise and Rollback if something wrong append.
|
||||
|
@ -40,7 +40,7 @@ class Members::ListService
|
||||
@query
|
||||
end
|
||||
|
||||
def search(current_user, query, subscription)
|
||||
def search(current_user, query, subscription, project)
|
||||
members = User.includes(:profile)
|
||||
.joins(:profile,
|
||||
:statistic_profile,
|
||||
@ -69,6 +69,10 @@ class Members::ListService
|
||||
members = members.where('subscriptions.id IS NULL OR subscriptions.expiration_date < :now', now: Date.today.to_s)
|
||||
end
|
||||
|
||||
if project == 'false' || project.blank?
|
||||
members = members.where("roles.name = 'member' OR roles.name = 'manager'")
|
||||
end
|
||||
|
||||
members.to_a
|
||||
end
|
||||
|
||||
|
@ -12,9 +12,10 @@ end
|
||||
|
||||
if @provider.providable_type == OpenIdConnectProvider.name
|
||||
json.providable_attributes do
|
||||
json.extract! @provider.providable, :id, :issuer, :discovery, :client_auth_method, :scope,
|
||||
json.extract! @provider.providable, :id, :issuer, :discovery, :client_auth_method,
|
||||
:prompt, :send_scope_to_token_endpoint, :client__identifier, :client__secret, :client__authorization_endpoint,
|
||||
:client__token_endpoint, :client__userinfo_endpoint, :client__jwks_uri, :client__end_session_endpoint, :profile_url
|
||||
json.scope @provider.providable[:scope]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -214,6 +214,7 @@ Rails.application.routes.draw do
|
||||
post 'payzen/check_hash' => 'payzen#check_hash'
|
||||
post 'payzen/create_token' => 'payzen#create_token'
|
||||
post 'payzen/update_token' => 'payzen#update_token'
|
||||
post 'payzen/check_cart' => 'payzen#check_cart'
|
||||
|
||||
# local payments handling
|
||||
post 'local_payment/confirm_payment' => 'local_payment#confirm_payment'
|
||||
|
@ -8,7 +8,6 @@ logfile_maxbytes=10MB ; maximum size of logfile befor
|
||||
logfile_backups=100 ; number of backed up logfiles
|
||||
loglevel=info ; info, debug, warn, trace
|
||||
pidfile=/var/run/supervisord.pid ; pidfile location
|
||||
user=root ; default user
|
||||
childlogdir=/var/log/supervisor/ ; where child log files will live
|
||||
|
||||
[supervisorctl]
|
||||
|
@ -30,7 +30,7 @@ module OmniAuth::Strategies
|
||||
|
||||
def authorize_params
|
||||
super.tap do |params|
|
||||
params[:scope] = active_provider.providable.scopes
|
||||
params[:scope] = OmniAuth::Strategies::SsoOauth2Provider.active_provider.providable.scopes
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "fab-manager",
|
||||
"version": "5.4.3",
|
||||
"version": "5.4.4",
|
||||
"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",
|
||||
|
30
scripts/use-relative-paths.sh
Executable file
30
scripts/use-relative-paths.sh
Executable file
@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# This script changes the paths in the docker-compose.yml file to use relative paths
|
||||
# Previously, we were using ${PWD} to get the path to the current directory, but this
|
||||
# caused issues when running a script from a different directory with "docker-compose -f".
|
||||
|
||||
config()
|
||||
{
|
||||
echo "Checking docker-compose file... "
|
||||
FABMANAGER_PATH=$(pwd)
|
||||
if [ ! -w "$FABMANAGER_PATH/docker-compose.yml" ]; then
|
||||
echo "Fab-manager's docker-compose.yml file not found or not writable."
|
||||
echo "Please run this script from the installation folder, and as a user having write access on docker-compose.yml"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
rename()
|
||||
{
|
||||
echo "Renaming paths... "
|
||||
sed -i.bak "s/\${PWD}/\./g" "$FABMANAGER_PATH/docker-compose.yml"
|
||||
}
|
||||
|
||||
proceed()
|
||||
{
|
||||
config
|
||||
rename
|
||||
}
|
||||
|
||||
proceed "$@"
|
@ -6,18 +6,18 @@ services:
|
||||
RAILS_ENV: production
|
||||
RACK_ENV: production
|
||||
env_file:
|
||||
- ${PWD}/config/env
|
||||
- ./config/env
|
||||
volumes:
|
||||
- ${PWD}/public/packs:/usr/src/app/public/packs
|
||||
- ${PWD}/public/uploads:/usr/src/app/public/uploads
|
||||
- ${PWD}/invoices:/usr/src/app/invoices
|
||||
- ${PWD}/payment_schedules:/usr/src/app/payment_schedules
|
||||
- ${PWD}/exports:/usr/src/app/exports
|
||||
- ${PWD}/imports:/usr/src/app/imports
|
||||
- ${PWD}/proof_of_identity_files:/usr/src/app/proof_of_identity_files
|
||||
- ${PWD}/log:/var/log/supervisor
|
||||
- ${PWD}/plugins:/usr/src/app/plugins
|
||||
- ${PWD}/accounting:/usr/src/app/accounting
|
||||
- ./public/packs:/usr/src/app/public/packs
|
||||
- ./public/uploads:/usr/src/app/public/uploads
|
||||
- ./invoices:/usr/src/app/invoices
|
||||
- ./payment_schedules:/usr/src/app/payment_schedules
|
||||
- ./exports:/usr/src/app/exports
|
||||
- ./imports:/usr/src/app/imports
|
||||
- ./proof_of_identity_files:/usr/src/app/proof_of_identity_files
|
||||
- ./log:/var/log/supervisor
|
||||
- ./plugins:/usr/src/app/plugins
|
||||
- ./accounting:/usr/src/app/accounting
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
@ -27,7 +27,7 @@ services:
|
||||
postgres:
|
||||
image: postgres:9.6
|
||||
volumes:
|
||||
- ${PWD}/postgresql:/var/lib/postgresql/data
|
||||
- ./postgresql:/var/lib/postgresql/data
|
||||
restart: always
|
||||
environment:
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
@ -41,14 +41,14 @@ services:
|
||||
soft: -1
|
||||
hard: -1
|
||||
volumes:
|
||||
- ${PWD}/elasticsearch/config:/usr/share/elasticsearch/config
|
||||
- ${PWD}/elasticsearch:/usr/share/elasticsearch/data
|
||||
- ./elasticsearch/config:/usr/share/elasticsearch/config
|
||||
- ./elasticsearch:/usr/share/elasticsearch/data
|
||||
restart: always
|
||||
|
||||
redis:
|
||||
image: redis:6-alpine
|
||||
volumes:
|
||||
- ${PWD}/redis:/data
|
||||
- ./redis:/data
|
||||
restart: always
|
||||
|
||||
nginx:
|
||||
@ -57,9 +57,9 @@ services:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ${PWD}/config/nginx:/etc/nginx/conf.d
|
||||
- ${PWD}/letsencrypt/etc:/etc/letsencrypt
|
||||
- ${PWD}/log:/var/log/nginx
|
||||
- ./config/nginx:/etc/nginx/conf.d
|
||||
- ./letsencrypt/etc:/etc/letsencrypt
|
||||
- ./log:/var/log/nginx
|
||||
volumes_from:
|
||||
- fabmanager:ro
|
||||
links:
|
||||
|
@ -117,7 +117,7 @@ elevate_cmd()
|
||||
read_email()
|
||||
{
|
||||
local email
|
||||
read -rp "Please input a valid email address > " email </dev/tty
|
||||
read -rep "Please input a valid email address > " email </dev/tty
|
||||
if [[ "$email" == *"@"*"."* ]]; then
|
||||
EMAIL="$email"
|
||||
else
|
||||
@ -152,7 +152,7 @@ config()
|
||||
|
||||
read_domain()
|
||||
{
|
||||
read -rp 'Please input the domain name > ' domain </dev/tty
|
||||
read -rep 'Please input the domain name > ' domain </dev/tty
|
||||
if [[ "$domain" == *"."* ]]; then
|
||||
DOMAINS+=("$domain")
|
||||
else
|
||||
@ -174,10 +174,15 @@ prepare_files()
|
||||
read -rp "Continue? (Y/n) " confirm </dev/tty
|
||||
if [[ "$confirm" = "n" ]]; then exit 1; fi
|
||||
|
||||
elevate_cmd mkdir -p "$FABMANAGER_PATH/config"
|
||||
elevate_cmd chown -R "$(whoami)" "$FABMANAGER_PATH"
|
||||
elevate_cmd mkdir -p "$FABMANAGER_PATH"
|
||||
elevate_cmd chown -R "$(whoami):$(whoami)" "$FABMANAGER_PATH"
|
||||
|
||||
mkdir -p "$FABMANAGER_PATH/elasticsearch/config"
|
||||
# create folders before starting the containers, otherwise root will own them
|
||||
local folders=(accounting config elasticsearch/config exports imports invoices log payment_schedules plugins postgresql \
|
||||
proof_of_identity_files public/packs public/uploads)
|
||||
for folder in "${folders[@]}"; do
|
||||
mkdir -p "$FABMANAGER_PATH/$folder"
|
||||
done
|
||||
|
||||
# Fab-manager environment variables
|
||||
\curl -sSL https://raw.githubusercontent.com/sleede/fab-manager/master/setup/env.example > "$FABMANAGER_PATH/config/env"
|
||||
@ -228,7 +233,7 @@ prepare_nginx()
|
||||
printf "The two following configurations are useful if you want to install Fab-manager behind a reverse proxy...\n"
|
||||
read -rp "- Do you want to map the Fab-manager's service to an external network? (Y/n) " confirm </dev/tty
|
||||
if [ "$confirm" != "n" ]; then
|
||||
read -rp "Please input the name of the external network (default: web) " network </dev/tty
|
||||
read -rep "Please input the name of the external network (default: web) " network </dev/tty
|
||||
if [ "$network" = "" ]; then network="web"; fi
|
||||
|
||||
echo "Adding a network configuration to the docker-compose.yml file..."
|
||||
@ -248,7 +253,7 @@ prepare_nginx()
|
||||
if [ "$confirm" != "n" ]; then
|
||||
current="$(yq eval '.services.*.image | select(. == "sleede/fab-manager*") | path | .[-2]' docker-compose.yml)"
|
||||
printf "=======================\n- \e[1mCurrent value: %s\e[21m\n- New value? (leave empty to keep the current value)\n" "$current"
|
||||
read -rp " > " value </dev/tty
|
||||
read -rep " > " value </dev/tty
|
||||
echo "======================="
|
||||
if [ "$value" != "" ]; then
|
||||
escaped=$(printf '%s\n' "$value" | iconv -f utf8 -t ascii//TRANSLIT//IGNORE | sed -e 's/[^a-zA-Z0-9-]/_/g')
|
||||
@ -331,7 +336,7 @@ configure_env_file()
|
||||
printf "**** \e[1mDocumentation:\e[21m ****\n"
|
||||
echo "$var_doc"
|
||||
printf "=======================\n- \e[1mCurrent value: %s\e[21m\n- New value? (leave empty to keep the current value)\n" "$current"
|
||||
read -rp " > " value </dev/tty
|
||||
read -rep " > " value </dev/tty
|
||||
echo "======================="
|
||||
if [ "$value" != "" ]; then
|
||||
esc_val=$(printf '%s\n' "$value" | sed -e 's/\//\\\//g')
|
||||
@ -340,7 +345,7 @@ configure_env_file()
|
||||
fi
|
||||
done
|
||||
# we automatically generate the SECRET_KEY_BASE
|
||||
secret=$(cd "$FABMANAGER_PATH" && docker-compose run --rm "$SERVICE" bundle exec rake secret)
|
||||
secret=$(docker-compose -f "$FABMANAGER_PATH/docker-compose.yml" run --user "$(id -u):$(id -g)" --rm "$SERVICE" bundle exec rake secret)
|
||||
sed -i.bak "s/SECRET_KEY_BASE=/SECRET_KEY_BASE=$secret/g" "$FABMANAGER_PATH/config/env"
|
||||
}
|
||||
|
||||
@ -370,32 +375,32 @@ setup_assets_and_databases()
|
||||
read -rp "Continue? (Y/n) " confirm </dev/tty
|
||||
if [ "$confirm" = "n" ]; then return; fi
|
||||
|
||||
cd "$FABMANAGER_PATH" && docker-compose run --rm "$SERVICE" bundle exec rake db:create # create the database
|
||||
cd "$FABMANAGER_PATH" && docker-compose run --rm "$SERVICE" bundle exec rake db:migrate # run all the migrations
|
||||
docker-compose -f "$FABMANAGER_PATH/docker-compose.yml" run --user "$(id -u):$(id -g)" --rm "$SERVICE" bundle exec rake db:create # create the database
|
||||
docker-compose -f "$FABMANAGER_PATH/docker-compose.yml" run --user "$(id -u):$(id -g)" --rm "$SERVICE" bundle exec rake db:migrate # run all the migrations
|
||||
# prompt default admin email/password
|
||||
printf "\n\nWe will now create the default administrator of Fab-manager.\n"
|
||||
read_email
|
||||
PASSWORD=$(read_password)
|
||||
printf "\nOK. We will fill the database now...\n"
|
||||
cd "$FABMANAGER_PATH" && docker-compose run --rm -e ADMIN_EMAIL="$EMAIL" -e ADMIN_PASSWORD="$PASSWORD" "$SERVICE" bundle exec rake db:seed # seed the database
|
||||
docker-compose -f "$FABMANAGER_PATH/docker-compose.yml" run --user "$(id -u):$(id -g)" --rm -e ADMIN_EMAIL="$EMAIL" -e ADMIN_PASSWORD="$PASSWORD" "$SERVICE" bundle exec rake db:seed # seed the database
|
||||
|
||||
# now build the assets
|
||||
if ! docker-compose -f "$FABMANAGER_PATH/docker-compose.yml" run --rm "$SERVICE" bundle exec rake assets:precompile; then
|
||||
if ! docker-compose -f "$FABMANAGER_PATH/docker-compose.yml" run --user "$(id -u):$(id -g)" --rm "$SERVICE" bundle exec rake assets:precompile; then
|
||||
echo -e "\e[91m[ ❌ ] someting went wrong while compiling the assets, exiting...\e[39m" && exit 1
|
||||
fi
|
||||
|
||||
# and prepare elasticsearch
|
||||
cd "$FABMANAGER_PATH" && docker-compose run --rm "$SERVICE" bundle exec rake fablab:es:build_stats
|
||||
docker-compose -f "$FABMANAGER_PATH/docker-compose.yml" run --user "$(id -u):$(id -g)" --rm "$SERVICE" bundle exec rake fablab:es:build_stats
|
||||
}
|
||||
|
||||
stop()
|
||||
{
|
||||
cd "$FABMANAGER_PATH" && docker-compose down
|
||||
docker-compose -f "$FABMANAGER_PATH/docker-compose.yml" down
|
||||
}
|
||||
|
||||
start()
|
||||
{
|
||||
cd "$FABMANAGER_PATH" && docker-compose up -d
|
||||
docker-compose -f "$FABMANAGER_PATH/docker-compose.yml" up -d
|
||||
}
|
||||
|
||||
enable_ssl()
|
||||
|
@ -40,7 +40,7 @@ yq() {
|
||||
}
|
||||
|
||||
jq() {
|
||||
docker run --rm -i -v "${PWD}:/data" imega/jq "$@"
|
||||
docker run --rm -i -v "${PWD}:/data" --user "$UID" imega/jq "$@"
|
||||
}
|
||||
|
||||
docker-compose()
|
||||
@ -58,6 +58,43 @@ docker-compose()
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
has_sudo()
|
||||
{
|
||||
local prompt
|
||||
|
||||
prompt=$(sudo -nv 2>&1)
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "has_sudo__pass_set"
|
||||
elif echo $prompt | grep -q '^sudo:'; then
|
||||
echo "has_sudo__needs_pass"
|
||||
else
|
||||
echo "no_sudo"
|
||||
fi
|
||||
}
|
||||
|
||||
elevate_cmd()
|
||||
{
|
||||
local cmd=$@
|
||||
|
||||
HAS_SUDO=$(has_sudo)
|
||||
|
||||
case "$HAS_SUDO" in
|
||||
has_sudo__pass_set)
|
||||
sudo $cmd
|
||||
;;
|
||||
has_sudo__needs_pass)
|
||||
echo "Please supply sudo password for the following command: sudo $cmd"
|
||||
sudo $cmd
|
||||
;;
|
||||
*)
|
||||
echo "Please supply root password for the following command: su -c \"$cmd\""
|
||||
su -c "$cmd"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
|
||||
# set $SERVICE and $YES_ALL
|
||||
config()
|
||||
{
|
||||
@ -125,9 +162,9 @@ version_error()
|
||||
# set $VERSION
|
||||
version_check()
|
||||
{
|
||||
VERSION=$(docker-compose exec -T "$SERVICE" cat .fabmanager-version 2>/dev/null)
|
||||
VERSION=$(docker-compose exec --user "$(id -u):$(id -g)" -T "$SERVICE" cat .fabmanager-version 2>/dev/null)
|
||||
if [[ $? = 1 ]]; then
|
||||
VERSION=$(docker-compose exec -T "$SERVICE" cat package.json | jq -r '.version')
|
||||
VERSION=$(docker-compose exec --user "$(id -u):$(id -g)" -T "$SERVICE" cat package.json | jq -r '.version')
|
||||
fi
|
||||
target_version
|
||||
if [ "$TARGET" = 'custom' ]; then return; fi
|
||||
@ -184,14 +221,18 @@ compile_assets()
|
||||
fi
|
||||
PG_NET_ID=$(docker inspect "$PG_ID" -f "{{json .NetworkSettings.Networks }}" | jq -r '.[] .NetworkID')
|
||||
clean_env_file
|
||||
mkdir -p public/new_packs
|
||||
# shellcheck disable=SC2068
|
||||
if ! docker run --rm --env-file ./config/env ${ENV_ARGS[@]} --link "$PG_ID" --net "$PG_NET_ID" -v "${PWD}/public/new_packs:/usr/src/app/public/packs" "$IMAGE" bundle exec rake assets:precompile; then
|
||||
restore_tag
|
||||
printf "\e[91m[ ❌ ] Something went wrong while compiling the assets, please check the logs above.\e[39m\nExiting...\n"
|
||||
exit 4
|
||||
if ! docker run --user "$(id -u):$(id -g)" --rm --env-file ./config/env ${ENV_ARGS[@]} --link "$PG_ID" --net "$PG_NET_ID" -v "${PWD}/public/new_packs:/usr/src/app/public/packs" "$IMAGE" bundle exec rake assets:precompile; then
|
||||
printf "\e[93m[ ⚠ ] Something may have went wrong while compiling the assets, please check the logs above.\e[39m\n"
|
||||
[[ "$YES_ALL" = "true" ]] && confirm="y" || read -rp "[91m::[0m [1mIgnore and continue?[0m (Y/n) " confirm </dev/tty
|
||||
if [[ "$confirm" = "n" ]]; then restore_tag; echo "Exiting..."; exit 4; fi
|
||||
fi
|
||||
docker-compose down
|
||||
rm -rf public/packs
|
||||
if ! rm -rf public/packs; then
|
||||
# sometimes we can't delete the packs folder, because of a permission issue. In that case try with sudo
|
||||
elevate_cmd rm -rf public/packs
|
||||
fi
|
||||
mv public/new_packs public/packs
|
||||
}
|
||||
|
||||
@ -239,21 +280,21 @@ upgrade()
|
||||
done
|
||||
for PRE in "${PREPROCESSING[@]}"; do
|
||||
printf "\e[91m::\e[0m \e[1mRunning preprocessing command %s...\e[0m\n" "$PRE"
|
||||
if ! docker-compose run --rm "$SERVICE" bundle exec "$PRE" </dev/tty; then
|
||||
if ! docker-compose run --user "$(id -u):$(id -g)" --rm "$SERVICE" bundle exec "$PRE" </dev/tty; then
|
||||
restore_tag
|
||||
printf "\e[91m[ ❌ ] Something went wrong while running \"%s\", please check the logs above.\e[39m\nExiting...\n" "$PRE"
|
||||
exit 4
|
||||
fi
|
||||
done
|
||||
compile_assets
|
||||
if ! docker-compose run --rm "$SERVICE" bundle exec rake db:migrate; then
|
||||
if ! docker-compose run --user "$(id -u):$(id -g)" --rm "$SERVICE" bundle exec rake db:migrate; then
|
||||
restore_tag
|
||||
printf "\e[91m[ ❌ ] Something went wrong while migrating the database, please check the logs above.\e[39m\nExiting...\n"
|
||||
exit 4
|
||||
fi
|
||||
for COMMAND in "${COMMANDS[@]}"; do
|
||||
printf "\e[91m::\e[0m \e[1mRunning command %s...\e[0m\n" "$COMMAND"
|
||||
if ! docker-compose run --rm "$SERVICE" bundle exec "$COMMAND" </dev/tty; then
|
||||
if ! docker-compose run --user "$(id -u):$(id -g)" --rm "$SERVICE" bundle exec "$COMMAND" </dev/tty; then
|
||||
restore_tag
|
||||
printf "\e[91m[ ❌ ] Something went wrong while running \"%s\", please check the logs above.\e[39m\nExiting...\n" "$COMMAND"
|
||||
exit 4
|
||||
|
@ -141,7 +141,7 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest
|
||||
end
|
||||
|
||||
assert_equal 422, response.status
|
||||
assert_match /slot is restricted for subscribers/, response.body
|
||||
assert_match /unable to pay/, response.body
|
||||
|
||||
assert_equal reservations_count, Reservation.count
|
||||
assert_equal invoices_count, Invoice.count
|
||||
|
Loading…
Reference in New Issue
Block a user