1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-02-26 20:54:21 +01:00

Merge branch 'dev' for release 4.7.4

This commit is contained in:
Sylvain 2021-03-08 15:40:32 +01:00
commit 2666c579d2
31 changed files with 248 additions and 66 deletions

View File

@ -1,5 +1,16 @@
# Changelog Fab-manager
## v4.7.4 2021 March 08
- Show remaining training credits in the dashboard
- Allow writing short rich descriptions for each subscription plan
- Allow inserting hyperlinks in customized info messages
- Use the primary color to display plans' price in the public view
- Do not close login modal when clicking on the backdrop
- Improved scripts for mounting volumes
- Increased verbosity of upgrade script
- Fix a bug: mounting the payment-schedules volume in the docker-compose file results in an invalid file
- [TODO DEPLOY] `rails fablab:maintenance:rebuild_stylesheet`
## v4.7.3 2021 March 03
- Improved the setup script
- Fix a bug: unable to install a new instance with an external reverse proxy
@ -13,7 +24,7 @@
- Fix a bug: unable to upgrade using the easy upgrade command
- Fix a security issue: possible SQL injection when dropping the database
- Fix a security issue: restrict allowed keys when creating/updating credits
- [TODO DEPLOY] `bundle exec rails fablab:openlab:bulk_export` if you have enabled OpenLab (projects sharing)
- [TODO DEPLOY] `rails fablab:openlab:bulk_export` if you have enabled OpenLab (projects sharing)
## v4.7.1 2021 February 24
- Fix a security issue: updated axios to 0.21.1 to fix [CVE-2020-28168](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-28168)

View File

@ -68,7 +68,7 @@ class API::PlansController < API::ApiController
@parameters = @parameters.require(:plan)
.permit(:base_name, :type, :group_id, :amount, :interval, :interval_count, :is_rolling,
:training_credit_nb, :ui_weight, :disabled, :monthly_payment,
:training_credit_nb, :ui_weight, :disabled, :monthly_payment, :description,
plan_file_attributes: %i[id attachment _destroy],
prices_attributes: %i[id amount])
end

View File

@ -71,6 +71,12 @@ const PlanCard: React.FC<PlanCardProps> = ({ plan, userId, subscribedPlanId, ope
const hasAttachment = (): boolean => {
return !!plan.plan_file_url;
}
/**
* Check if the plan has a description
*/
const hasDescription = (): boolean => {
return !!plan.description;
}
/**
* Check if the plan is allowing a monthly payment schedule
*/
@ -100,25 +106,28 @@ const PlanCard: React.FC<PlanCardProps> = ({ plan, userId, subscribedPlanId, ope
</div>
</div>}
</div>
{canSubscribeForMe() && <div className="cta-button">
{!hasSubscribedToThisPlan() && <button className={`subscribe-button ${isSelected ? 'selected-card' : ''}`}
onClick={handleSelectPlan}
disabled={!_.isNil(subscribedPlanId)}>
{userId && <span>{t('app.public.plans.i_choose_that_plan')}</span>}
{!userId && <span>{t('app.public.plans.i_subscribe_online')}</span>}
</button>}
{hasSubscribedToThisPlan() && <button className="subscribe-button selected-card" disabled>
{ t('app.public.plans.i_already_subscribed') }
</button>}
</div>}
{canSubscribeForOther() && <div className="cta-button">
<button className={`subscribe-button ${isSelected ? 'selected-card' : ''}`}
onClick={handleSelectPlan}
disabled={_.isNil(userId)}>
<span>{ t('app.public.plans.i_choose_that_plan') }</span>
</button>
</div>}
{hasAttachment() && <a className="info-link" href={ plan.plan_file_url } target="_blank">{ t('app.public.plans.more_information') }</a>}
<div className="card-footer">
{hasDescription() && <div className="plan-description" dangerouslySetInnerHTML={{__html: plan.description}}/>}
{hasAttachment() && <a className="info-link" href={ plan.plan_file_url } target="_blank">{ t('app.public.plans.more_information') }</a>}
{canSubscribeForMe() && <div className="cta-button">
{!hasSubscribedToThisPlan() && <button className={`subscribe-button ${isSelected ? 'selected-card' : ''}`}
onClick={handleSelectPlan}
disabled={!_.isNil(subscribedPlanId)}>
{userId && <span>{t('app.public.plans.i_choose_that_plan')}</span>}
{!userId && <span>{t('app.public.plans.i_subscribe_online')}</span>}
</button>}
{hasSubscribedToThisPlan() && <button className="subscribe-button selected-card" disabled>
{ t('app.public.plans.i_already_subscribed') }
</button>}
</div>}
{canSubscribeForOther() && <div className="cta-button">
<button className={`subscribe-button ${isSelected ? 'selected-card' : ''}`}
onClick={handleSelectPlan}
disabled={_.isNil(userId)}>
<span>{ t('app.public.plans.i_choose_that_plan') }</span>
</button>
</div>}
</div>
</div>
);
}

View File

@ -64,6 +64,14 @@ class PlanController {
return file._destroy = true;
}
};
/**
* Check and limit
* @param content
*/
$scope.limitDescriptionSize = function (content) {
alert(content);
};
}
}

View File

@ -408,6 +408,7 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco
<% else %>
return $uibModal.open({
templateUrl: '/shared/deviseModal.html',
backdrop: 'static',
size: 'sm',
resolve: {
settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['confirmation_required']" }).$promise; }]

View File

@ -12,7 +12,7 @@
*/
'use strict';
Application.Controllers.controller('DashboardController', ['$scope', 'memberPromise', 'SocialNetworks', function ($scope, memberPromise, SocialNetworks) {
Application.Controllers.controller('DashboardController', ['$scope', 'memberPromise', 'trainingsPromise', 'SocialNetworks', function ($scope, memberPromise, trainingsPromise, SocialNetworks) {
// Current user's profile
$scope.user = memberPromise;
@ -22,6 +22,24 @@ Application.Controllers.controller('DashboardController', ['$scope', 'memberProm
networks: SocialNetworks
};
/**
* Check if the member has used his training credits for the given credit
* @param trainingCredits array of credits used by the member
* @param trainingId id of the training to find
*/
$scope.hasUsedTrainingCredit = function (trainingCredits, trainingId) {
return trainingCredits.find(tc => tc.training_id === trainingId);
};
/**
* Return the name associated with the provided training ID
* @param trainingId training identifier
* @return {string}
*/
$scope.getTrainingName = function (trainingId) {
return trainingsPromise.find(t => t.id === trainingId).name;
};
/* PRIVATE SCOPE */
/**

View File

@ -143,7 +143,8 @@ angular.module('application.router', ['ui.router'])
abstract: true,
url: '/dashboard',
resolve: {
memberPromise: ['Member', 'currentUser', function (Member, currentUser) { return Member.get({ id: currentUser.id }).$promise; }]
memberPromise: ['Member', 'currentUser', function (Member, currentUser) { return Member.get({ id: currentUser.id }).$promise; }],
trainingsPromise: ['Training', function (Training) { return Training.query().$promise; }]
}
})
.state('app.logged.dashboard.profile', {

View File

@ -269,6 +269,7 @@
.pricing-panel {
border: 1px solid $border-color;
height: 391px;
&:first-child {
border-right: none;
@ -280,6 +281,13 @@
@include border-radius(0 3px 3px 0);
}
.plan-card {
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.title {
margin: 10px 0;
font-size: rem-calc(16);
@ -347,27 +355,39 @@
}
}
.cta-button {
margin: 20px 0;
.card-footer {
display: flex;
flex-direction: column;
justify-content: space-around;
height: 100%;
.subscribe-button {
@extend .btn;
@extend .rounded;
.plan-description {
max-height: 5.2em;
overflow: hidden;
}
outline: 0;
font-weight: 600;
font-size: rem-calc(16);
background-color: white;
padding-left: 30px;
padding-right: 30px;
.cta-button {
margin: 20px 0;
.subscribe-button {
@extend .btn;
@extend .rounded;
outline: 0;
font-weight: 600;
font-size: rem-calc(16);
background-color: white;
padding-left: 30px;
padding-right: 30px;
}
button.subscribe-button:focus, button.subscribe-button:hover {
outline: 0;
}
}
button.subscribe-button:focus, button.subscribe-button:hover {
outline: 0;
.info-link {
margin-top: 1em;
}
}
.info-link {
margin-top: 1em;
}
}
.well {
@ -800,3 +820,15 @@ input[type=date].form-control {
margin-left: 1em;
}
}
.medium-editor-input {
display: table-cell;
border: 1px solid #c0c0c0;
border-radius: 0.2em;
padding: 0.5em;
width: 100%;
p {
margin-bottom: 0;
}
}

View File

@ -686,3 +686,18 @@ body.container {
text-align: center;
vertical-align: middle;
}
.plan-description-input .medium-editor-input div[medium-editor] {
max-height: 5.2em;
overflow: hidden;
& p:nth-child(2n+3), p:nth-child(2n+4) {
display: none;
}
}
.close-modal-button {
position: absolute;
right: 13px;
cursor: pointer;
}

View File

@ -127,6 +127,17 @@
<span class="help-block" translate>{{ 'app.shared.plan.monthly_payment_info' }}</span>
</div>
<div class="input-group m-t-md plan-description-input">
<label for="plan[description]" class="control-label m-r-md" translate>{{ 'app.shared.plan.description' }}</label>
<div class="medium-editor-input">
<div ng-model="plan.description" medium-editor options='{"placeholder": "{{ "app.shared.plan.type_a_short_description" | translate }}",
"buttons": ["bold", "italic", "anchor", "unorderedlist", "header2" ]
}'>
</div>
</div>
<input type="hidden" id="plan[description]" name="plan[description]" value="{{plan.description}}" />
</div>
<!-- PDF description attachement -->
<input type="hidden" ng-model="plan.plan_file_attributes.id" name="plan[plan_file_attributes][id]" ng-value="plan.plan_file_attributes.id" />
<input type="hidden" ng-model="plan.plan_file_attributes._destroy" name="plan[plan_file_attributes][_destroy]" ng-value="plan.plan_file_attributes._destroy"/>

View File

@ -49,7 +49,7 @@
<div class="col-md-3">
<h4 translate>{{ 'app.admin.settings.message_of_the_machine_booking_page' }}</h4>
<div ng-model="machineExplicationsAlert.value" medium-editor options='{"placeholder": "{{ "app.admin.settings.type_the_message_content" | translate }}",
"buttons": ["bold", "italic", "unorderedlist", "header2" ]
"buttons": ["bold", "italic", "anchor", "unorderedlist", "header2" ]
}'>
</div>
@ -58,7 +58,7 @@
<div class="col-md-3">
<h4 translate>{{ 'app.admin.settings.warning_message_of_the_training_booking_page'}}</h4>
<div ng-model="trainingExplicationsAlert.value" medium-editor options='{"placeholder": "{{ "app.admin.settings.type_the_message_content" | translate }}",
"buttons": ["bold", "italic", "unorderedlist", "header2" ]
"buttons": ["bold", "italic", "anchor", "unorderedlist", "header2" ]
}'>
</div>
@ -67,7 +67,7 @@
<div class="col-md-3">
<h4 translate>{{ 'app.admin.settings.information_message_of_the_training_reservation_page'}}</h4>
<div ng-model="trainingInformationMessage.value" medium-editor options='{"placeholder": "{{ "app.admin.settings.type_the_message_content" | translate }}",
"buttons": ["bold", "italic", "unorderedlist", "header2" ]
"buttons": ["bold", "italic", "anchor", "unorderedlist", "header2" ]
}'>
</div>
@ -76,7 +76,7 @@
<div class="col-md-3">
<h4 translate>{{ 'app.admin.settings.message_of_the_subscriptions_page' }}</h4>
<div ng-model="subscriptionExplicationsAlert.value" medium-editor options='{"placeholder": "{{ "app.admin.settings.type_the_message_content" | translate }}",
"buttons": ["bold", "italic", "unorderedlist", "header2" ]
"buttons": ["bold", "italic", "anchor", "unorderedlist", "header2" ]
}'>
</div>
<button name="button" class="btn btn-warning" ng-click="save(subscriptionExplicationsAlert)" translate>{{ 'app.shared.buttons.save' }}</button>
@ -84,7 +84,7 @@
<div class="col-md-3">
<h4 translate>{{ 'app.admin.settings.message_of_the_events_page' }}</h4>
<div ng-model="eventExplicationsAlert.value" medium-editor options='{"placeholder": "{{ "app.admin.settings.type_the_message_content" | translate }}",
"buttons": ["bold", "italic", "unorderedlist", "header2" ]
"buttons": ["bold", "italic", "anchor", "unorderedlist", "header2" ]
}'>
</div>
<button name="button" class="btn btn-warning" ng-click="save(eventExplicationsAlert)" translate>{{ 'app.shared.buttons.save' }}</button>
@ -92,7 +92,7 @@
<div class="col-md-3" ng-show="$root.modules.spaces">
<h4 translate>{{ 'app.admin.settings.message_of_the_spaces_page' }}</h4>
<div ng-model="spaceExplicationsAlert.value" medium-editor options='{"placeholder": "{{ "app.admin.settings.type_the_message_content" | translate }}",
"buttons": ["bold", "italic", "unorderedlist", "header2" ]
"buttons": ["bold", "italic", "anchor", "unorderedlist", "header2" ]
}'>
</div>
<button name="button" class="btn btn-warning" ng-click="save(spaceExplicationsAlert)" translate>{{ 'app.shared.buttons.save' }}</button>

View File

@ -7,11 +7,33 @@
</section>
<div class="row no-gutter">
<div class="col-md-10">
<div class="widget panel b-a m m-t-lg">
<div class="panel-heading b-b">
<h4 class="text-u-c"><i class="fa fa-tag m-r-xs"></i>{{ 'app.logged.dashboard.trainings.your_training_credits' | translate }}</h4>
</div>
<div class="widget-content bg-light wrapper r-b">
<span ng-show="!user.subscribed_plan" translate>{{ 'app.logged.dashboard.trainings.subscribe_for_credits' }}</span>
<span ng-show="user.subscribed_plan" translate>{{ 'app.logged.dashboard.trainings.register_for_free' }}</span>
<ul ng-if="user.subscribed_plan" class="list-unstyled">
<li ng-repeat="c in user.subscribed_plan.training_credits" ng-show="!hasUsedTrainingCredit(user.training_credits, c.training_id)">
{{getTrainingName(c.training_id)}}
<button type="button" class="btn btn-default m-l btn-sm" ui-sref="app.logged.trainings_reserve({id: c.training_id})" translate>
{{ 'app.logged.dashboard.trainings.book_here' }}
</button>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="row no-gutter">
<div class="col-md-4">
<div class="widget panel b-a m m-t-lg">
<div class="widget panel b-a m">
<div class="panel-heading b-b">
<h4 class="text-u-c"><i class="fa fa-tag m-r-xs"></i> {{ 'app.logged.dashboard.trainings.your_next_trainings' | translate }}</h4>
</div>

View File

@ -1,6 +1,7 @@
<div class="" id="loginModal">
<div class="modal-header">
<img ng-src="{{logoBlack.custom_asset_file_attributes.attachment_url}}" alt="{{logo.custom_asset_file_attributes.attachment}}" class="modal-logo"/>
<i class="fa fa-times close-modal-button" ng-click="dismiss()"></i>
<h1 translate translate-default="Login">
{{ 'app.public.common.connection' }}
</h1>

View File

@ -259,9 +259,14 @@ h5:after {
border-color: $secondary;
}
.pricing-panel .cta-button .btn:hover,
.pricing-panel .cta-button .custom-invoice .modal-body .elements li:hover,
.custom-invoice .modal-body .elements .pricing-panel .cta-button li:hover {
.pricing-panel .plan-card .content .price {
background-color: $primary;
color: $primary-text-color;
}
.pricing-panel .card-footer .cta-button .btn:hover,
.pricing-panel .card-footer .cta-button .custom-invoice .modal-body .elements li:hover,
.custom-invoice .modal-body .elements .pricing-panel .card-footer .cta-button li:hover {
background-color: $secondary !important;
color: $secondary-text-color;
}
@ -302,11 +307,14 @@ section#cookies-modal div.cookies-consent .cookies-actions button.accept {
}
.pricing-panel {
.cta-button {
button.subscribe-button {
border-color: $secondary;
&.selected-card {
background-color: $secondary;
.card-footer {
.cta-button {
button.subscribe-button {
border-color: $secondary;
&.selected-card {
background-color: $secondary;
}
}
}
}

View File

@ -109,6 +109,10 @@ de:
your_previous_trainings: "Ihre vorigen Schulungen"
your_approved_trainings: "Ihre bestätigten Trainings"
no_trainings: "Keine Schulungen"
your_training_credits: "Your training credits"
subscribe_for_credits: "Subscribe to benefit from free trainings"
register_for_free: "Register for free to the following trainings:"
book_here: "Book here"
#dashboard: my events
events:
your_next_events: "Ihre nächsten Termine"

View File

@ -109,6 +109,10 @@ en:
your_previous_trainings: "Your previous trainings"
your_approved_trainings: "Your approved trainings"
no_trainings: "No trainings"
your_training_credits: "Your training credits"
subscribe_for_credits: "Subscribe to benefit from free trainings"
register_for_free: "Register for free to the following trainings:"
book_here: "Book here"
#dashboard: my events
events:
your_next_events: "Your next events"

View File

@ -109,6 +109,10 @@ es:
your_previous_trainings: "Sus cursos anteriores"
your_approved_trainings: "Sus cursos aprobados"
no_trainings: "No trainings"
your_training_credits: "Your training credits"
subscribe_for_credits: "Subscribe to benefit from free trainings"
register_for_free: "Register for free to the following trainings:"
book_here: "Book here"
#dashboard: my events
events:
your_next_events: "Sus próximos eventos"

View File

@ -109,6 +109,10 @@ fr:
your_previous_trainings: "Vos formations passées"
your_approved_trainings: "Vos formations validées"
no_trainings: "Aucune formation"
your_training_credits: "Vos crédits formation"
subscribe_for_credits: "Abonnez-vous pour bénéficier de formations gratuites"
register_for_free: "Inscrivez-vous gratuitement aux formations suivantes :"
book_here: "Réserver"
#dashboard: my events
events:
your_next_events: "Vos prochains événements"

View File

@ -109,6 +109,10 @@ pt:
your_previous_trainings: "Seus treinamentos anteriores"
your_approved_trainings: "Seus treinamentos aprovados"
no_trainings: "Sem treinamentos"
your_training_credits: "Your training credits"
subscribe_for_credits: "Subscribe to benefit from free trainings"
register_for_free: "Register for free to the following trainings:"
book_here: "Book here"
#dashboard: my events
events:
your_next_events: "Seus próximos eventos"

View File

@ -109,6 +109,10 @@ zu:
your_previous_trainings: "crwdns8693:0crwdne8693:0"
your_approved_trainings: "crwdns8695:0crwdne8695:0"
no_trainings: "crwdns8697:0crwdne8697:0"
your_training_credits: "crwdns21426:0crwdne21426:0"
subscribe_for_credits: "crwdns21428:0crwdne21428:0"
register_for_free: "crwdns21430:0crwdne21430:0"
book_here: "crwdns21432:0crwdne21432:0"
#dashboard: my events
events:
your_next_events: "crwdns8699:0crwdne8699:0"

View File

@ -192,6 +192,8 @@ de:
otherwise_it_will_begin_as_soon_as_it_is_bought: "Andernfalls beginnt es ab Kaufdatum."
monthly_payment: "Monthly payment?"
monthly_payment_info: "If monthly payment is enabled, the members will be able to choose between a one-time payment or a payment schedule staged each months."
description: "Description"
type_a_short_description: "Type a short description"
information_sheet: "Informationsblatt"
attach_an_information_sheet: "Ein Informationsblatt anhängen"
notified_partner: "Benachrichtigter Partner"

View File

@ -192,6 +192,8 @@ en:
otherwise_it_will_begin_as_soon_as_it_is_bought: "Otherwise, it will begin as soon as it is bought."
monthly_payment: "Monthly payment?"
monthly_payment_info: "If monthly payment is enabled, the members will be able to choose between a one-time payment or a payment schedule staged each months."
description: "Description"
type_a_short_description: "Type a short description"
information_sheet: "Information sheet"
attach_an_information_sheet: "Attach an information sheet"
notified_partner: "Notified partner"

View File

@ -192,6 +192,8 @@ es:
otherwise_it_will_begin_as_soon_as_it_is_bought: "De otro modo, empezará tan pronto como se haya adquirido."
monthly_payment: "Monthly payment?"
monthly_payment_info: "If monthly payment is enabled, the members will be able to choose between a one-time payment or a payment schedule staged each months."
description: "Description"
type_a_short_description: "Type a short description"
information_sheet: "hoja de información"
attach_an_information_sheet: "adjuntar una hoja de infomación"
notified_partner: "Compañero notificado"

View File

@ -192,6 +192,8 @@ fr:
otherwise_it_will_begin_as_soon_as_it_is_bought: "Dans le cas contraire, il prendra effet dès sa date d'achat."
monthly_payment: "Paiement mensuel ?"
monthly_payment_info: "Si le paiement mensuel est activé, les membres pourront choisir entre un paiement unique ou un échéancier de paiement échelonné chaque mois."
description: "Description"
type_a_short_description: "Saisir une courte description"
information_sheet: "Fiche descriptive"
attach_an_information_sheet: "Joindre une fiche descriptive"
notified_partner: "Partenaire notifié"

View File

@ -192,6 +192,8 @@ pt:
otherwise_it_will_begin_as_soon_as_it_is_bought: "Caso contrário, elecomeçará assim que for comprado."
monthly_payment: "Monthly payment?"
monthly_payment_info: "If monthly payment is enabled, the members will be able to choose between a one-time payment or a payment schedule staged each months."
description: "Description"
type_a_short_description: "Type a short description"
information_sheet: "Folha de informação"
attach_an_information_sheet: "Anexar folha de informação"
notified_partner: "Parceiro notificado"

View File

@ -192,6 +192,8 @@ zu:
otherwise_it_will_begin_as_soon_as_it_is_bought: "crwdns9687:0crwdne9687:0"
monthly_payment: "crwdns20936:0crwdne20936:0"
monthly_payment_info: "crwdns20938:0crwdne20938:0"
description: "crwdns21422:0crwdne21422:0"
type_a_short_description: "crwdns21424:0crwdne21424:0"
information_sheet: "crwdns9689:0crwdne9689:0"
attach_an_information_sheet: "crwdns9691:0crwdne9691:0"
notified_partner: "crwdns9693:0crwdne9693:0"

View File

@ -1,6 +1,6 @@
{
"name": "fab-manager",
"version": "4.7.3",
"version": "4.7.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",

View File

@ -18,9 +18,11 @@ config()
add_mount()
{
# shellcheck disable=SC2016
# we don't want to expand ${PWD}
yq -i eval ".services.$SERVICE.volumes += [\"\${PWD}/payment_schedules:/usr/src/app/payment_schedules\"]" docker-compose.yml
if [[ ! $(yq eval ".services.$SERVICE.volumes.[] | select (. == \"*payment_schedules\")" docker-compose.yml) ]]; then
# shellcheck disable=SC2016
# we don't want to expand ${PWD}
yq -i eval ".services.$SERVICE.volumes += [\"\${PWD}/payment_schedules:/usr/src/app/payment_schedules\"]" docker-compose.yml
fi
}
proceed()

View File

@ -18,8 +18,10 @@ config()
change_mount()
{
yq -i eval ".services.$SERVICE.volumes.[] | select(. == \"*assets\") |= \"\${PWD}/public/packs:/usr/src/app/public/packs\"" docker-compose.yml
echo "Service volume was replaced for $SERVICE: /assets changed to /packs"
if [[ $(yq eval ".services.$SERVICE.volumes.[] | select (. == \"*assets\")" docker-compose.yml) ]]; then
yq -i eval ".services.$SERVICE.volumes.[] |= select(. == \"*assets\") |= \"\${PWD}/public/packs:/usr/src/app/public/packs\"" docker-compose.yml
echo "Service volume was replaced for $SERVICE: /assets changed to /packs"
fi
}
proceed()

View File

@ -66,6 +66,7 @@ read_email()
config()
{
SERVICE="fabmanager"
echo 'We recommend nginx to serve the application over the network (internet). You can use your own solution or let this script install and configure nginx for Fab-manager.'
read -rp 'Do you want install nginx? (Y/n) ' NGINX </dev/tty
if [ "$NGINX" != "n" ]; then
@ -180,6 +181,7 @@ prepare_nginx()
if [ "$value" != "" ]; then
escaped=$(printf '%s\n' "$value" | iconv -f utf8 -t ascii//TRANSLIT//IGNORE | sed -e 's/[^a-zA-Z0-9-]/_/g')
yq -i eval ".services.$escaped = .services.$current | del(.services.$current)" docker-compose.yml
SERVICE="$escaped"
fi
fi
fi
@ -265,7 +267,7 @@ configure_env_file()
fi
done
# we automatically generate the SECRET_KEY_BASE
secret=$(cd "$FABMANAGER_PATH" && docker-compose run --rm fabmanager bundle exec rake secret)
secret=$(cd "$FABMANAGER_PATH" && docker-compose run --rm "$SERVICE" bundle exec rake secret)
sed -i.bak "s/SECRET_KEY_BASE=/SECRET_KEY_BASE=$secret/g" "$FABMANAGER_PATH/config/env"
}
@ -295,20 +297,20 @@ 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 fabmanager bundle exec rake db:create # create the database
cd "$FABMANAGER_PATH" && docker-compose run --rm fabmanager bundle exec rake db:migrate # run all the migrations
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
# 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 fulfill the database now...\n"
cd "$FABMANAGER_PATH" && docker-compose run --rm -e ADMIN_EMAIL="$EMAIL" -e ADMIN_PASSWORD="$PASSWORD" fabmanager bundle exec rake db:seed # seed the database
cd "$FABMANAGER_PATH" && docker-compose run --rm -e ADMIN_EMAIL="$EMAIL" -e ADMIN_PASSWORD="$PASSWORD" "$SERVICE" bundle exec rake db:seed # seed the database
# now build the assets
cd "$FABMANAGER_PATH" && docker-compose run --rm fabmanager bundle exec rake assets:precompile
cd "$FABMANAGER_PATH" && docker-compose run --rm "$SERVICE" bundle exec rake assets:precompile
# and prepare elasticsearch
cd "$FABMANAGER_PATH" && docker-compose run --rm fabmanager bundle exec rake fablab:es:build_stats
cd "$FABMANAGER_PATH" && docker-compose run --rm "$SERVICE" bundle exec rake fablab:es:build_stats
}
stop()

View File

@ -87,6 +87,7 @@ add_environments()
{
for ENV in "${ENVIRONMENTS[@]}"; do
if [[ "$ENV" =~ ^[A-Z0-9_]+=.*$ ]]; then
printf "Inserting variable %s...\n" "$ENV"
printf "# added on %s\n%s\n" "$(date +%Y-%m-%d\ %R)" "$ENV" >> "config/env"
else
echo "Ignoring invalid option: -e $ENV. Given value is not valid environment variable, please see https://huit.re/environment-doc"
@ -125,6 +126,7 @@ upgrade()
BRANCH='master'
if yq eval '.services.*.image | select(. == "sleede/fab-manager*")' docker-compose.yml | grep -q ':dev'; then BRANCH='dev'; fi
for SCRIPT in "${SCRIPTS[@]}"; do
printf "Running script %s from branch %s...\n" "$SCRIPT" "$BRANCH"
if [[ "$YES_ALL" = "true" ]]; then
\curl -sSL "https://raw.githubusercontent.com/sleede/fab-manager/$BRANCH/scripts/$SCRIPT.sh" | bash -s -- -y
else
@ -134,6 +136,7 @@ upgrade()
compile_assets
docker-compose run --rm "$SERVICE" bundle exec rake db:migrate
for COMMAND in "${COMMANDS[@]}"; do
printf "Running command %s...\n" "$COMMAND"
docker-compose run --rm "$SERVICE" bundle exec "$COMMAND"
done
docker-compose up -d