mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-18 07:52:23 +01:00
Merge branch 'statisticprofile' into dev
This commit is contained in:
commit
971102ec1d
2
Procfile
2
Procfile
@ -1,3 +1,3 @@
|
||||
web: bundle exec rails server puma -p $PORT -b0.0.0.0
|
||||
#web: bundle exec rails server puma -p $PORT -b0.0.0.0
|
||||
worker: bundle exec sidekiq -C ./config/sidekiq.yml
|
||||
mail: bundle exec mailcatcher --foreground
|
||||
|
@ -264,8 +264,8 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
||||
* @return {string} 'male' or 'female'
|
||||
*/
|
||||
var getGender = function (user) {
|
||||
if (user.profile) {
|
||||
if (user.profile.gender === 'true') { return 'male'; } else { return 'female'; }
|
||||
if (user.statistic_profile) {
|
||||
if (user.statistic_profile.gender === 'true') { return 'male'; } else { return 'female'; }
|
||||
} else { return 'other'; }
|
||||
};
|
||||
|
||||
|
@ -225,8 +225,11 @@ Application.Controllers.controller('AdminMembersController', ['$scope', '$sce',
|
||||
* Callback when the search field content changes: reload the search results
|
||||
*/
|
||||
$scope.updateTextSearch = function () {
|
||||
resetSearchMember();
|
||||
return memberSearch();
|
||||
if (searchTimeout) clearTimeout(searchTimeout);
|
||||
searchTimeout = setTimeout(function() {
|
||||
resetSearchMember();
|
||||
memberSearch();
|
||||
}, 300);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -252,6 +255,11 @@ Application.Controllers.controller('AdminMembersController', ['$scope', '$sce',
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Will temporize the search query to prevent overloading the API
|
||||
*/
|
||||
var searchTimeout = null;
|
||||
|
||||
/**
|
||||
* Iterate through the provided array and return the index of the requested admin
|
||||
* @param admins {Array} full list of users with role 'admin'
|
||||
@ -267,13 +275,13 @@ Application.Controllers.controller('AdminMembersController', ['$scope', '$sce',
|
||||
*/
|
||||
var resetSearchMember = function () {
|
||||
$scope.member.noMore = false;
|
||||
return $scope.member.page = 1;
|
||||
$scope.member.page = 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Run a search query with the current parameters set ($scope.member[searchText,order,page])
|
||||
* and affect or append the result in $scope.members, depending on the concat parameter
|
||||
* @param concat {boolean} if true, the result will be append to $scope.members instead of being affected
|
||||
* @param [concat] {boolean} if true, the result will be append to $scope.members instead of being affected
|
||||
*/
|
||||
var memberSearch = function (concat) {
|
||||
Member.list({
|
||||
@ -536,7 +544,7 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state',
|
||||
CSRF.setMetaTags();
|
||||
|
||||
// init the birth date to JS object
|
||||
$scope.user.profile.birthday = moment($scope.user.profile.birthday).toDate();
|
||||
$scope.user.statistic_profile.birthday = moment($scope.user.statistic_profile.birthday).toDate();
|
||||
|
||||
// the user subscription
|
||||
if (($scope.user.subscribed_plan != null) && ($scope.user.subscription != null)) {
|
||||
@ -579,7 +587,11 @@ Application.Controllers.controller('NewMemberController', ['$scope', '$state', '
|
||||
$scope.password = { change: false };
|
||||
|
||||
// Default member's profile parameters
|
||||
$scope.user = { plan_interval: '' };
|
||||
$scope.user = {
|
||||
plan_interval: '',
|
||||
invoicing_profile: {},
|
||||
statistic_profile: {}
|
||||
};
|
||||
|
||||
// Callback when the admin check/uncheck the box telling that the new user is an organization.
|
||||
// Disable or enable the organization fields in the form, accordingly
|
||||
@ -604,9 +616,10 @@ Application.Controllers.controller('NewAdminController', ['$state', '$scope', 'A
|
||||
// default admin profile
|
||||
let getGender;
|
||||
$scope.admin = {
|
||||
profile_attributes: {
|
||||
statistic_profile_attributes: {
|
||||
gender: true
|
||||
},
|
||||
profile_attributes: {},
|
||||
invoicing_profile_attributes: {}
|
||||
};
|
||||
|
||||
@ -650,8 +663,8 @@ Application.Controllers.controller('NewAdminController', ['$state', '$scope', 'A
|
||||
* @return {string} 'male' or 'female'
|
||||
*/
|
||||
return getGender = function (user) {
|
||||
if (user.profile_attributes) {
|
||||
if (user.profile_attributes.gender) { return 'male'; } else { return 'female'; }
|
||||
if (user.statistic_profile_attributes) {
|
||||
if (user.statistic_profile_attributes.gender) { return 'male'; } else { return 'female'; }
|
||||
} else { return 'other'; }
|
||||
};
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco
|
||||
return $uibModal.open({
|
||||
templateUrl: '<%= asset_path "shared/signupModal.html" %>',
|
||||
size: 'md',
|
||||
controller: ['$scope', '$uibModalInstance', 'Group', 'CustomAsset', function ($scope, $uibModalInstance, Group, CustomAsset) {
|
||||
controller: ['$scope', '$uibModalInstance', 'Group', 'CustomAsset', 'growl', '_t', function ($scope, $uibModalInstance, Group, CustomAsset, growl, _t) {
|
||||
// default parameters for the date picker in the account creation modal
|
||||
$scope.datePicker = {
|
||||
format: Fablab.uibDateFormat,
|
||||
@ -134,8 +134,13 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco
|
||||
delete $scope.user.organization;
|
||||
// register on server
|
||||
return Auth.register($scope.user).then(function (user) {
|
||||
// creation successful
|
||||
$uibModalInstance.close(user);
|
||||
if (user.id) {
|
||||
// creation successful
|
||||
$uibModalInstance.close(user);
|
||||
} else {
|
||||
// the user was not saved in database, something wrong occurred
|
||||
growl.error(_t('unexpected_error_occurred'));
|
||||
}
|
||||
}, function (error) {
|
||||
// creation failed...
|
||||
// restore organization param
|
||||
|
@ -258,7 +258,7 @@ Application.Controllers.controller('EditProfileController', ['$scope', '$rootSco
|
||||
CSRF.setMetaTags();
|
||||
|
||||
// init the birth date to JS object
|
||||
$scope.user.profile.birthday = moment($scope.user.profile.birthday).toDate();
|
||||
$scope.user.statistic_profile.birthday = moment($scope.user.statistic_profile.birthday).toDate();
|
||||
|
||||
if ($scope.activeProvider.providable_type !== 'DatabaseProvider') {
|
||||
$scope.preventPassword = true;
|
||||
|
@ -150,8 +150,8 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
|
||||
* @return {string} 'male' or 'female'
|
||||
*/
|
||||
$scope.getGender = function (user) {
|
||||
if (user && user.profile) {
|
||||
if (user.profile.gender === 'true') { return 'male'; } else { return 'female'; }
|
||||
if (user && user.statistic_profile) {
|
||||
if (user.statistic_profile.gender === 'true') { return 'male'; } else { return 'female'; }
|
||||
} else { return 'other'; }
|
||||
};
|
||||
|
||||
|
@ -206,7 +206,7 @@ Application.Controllers.controller('CompleteProfileController', ['$scope', '$roo
|
||||
CSRF.setMetaTags();
|
||||
|
||||
// init the birth date to JS object
|
||||
$scope.user.profile.birthday = moment($scope.user.profile.birthday).toDate();
|
||||
$scope.user.statistic_profile.birthday = moment($scope.user.statistic_profile.birthday).toDate();
|
||||
|
||||
// bind fields protection with sso fields
|
||||
angular.forEach(activeProviderPromise.mapping, function (map) { $scope.preventField[map] = true; });
|
||||
|
@ -1,18 +1,18 @@
|
||||
<div class="row m-t">
|
||||
<div class="col-sm-offset-3 col-sm-6">
|
||||
<div class="form-group" ng-class="{'has-error': adminForm['admin[profile_attributes][gender]'].$dirty && adminForm['admin[profile_attributes][gender]'].$invalid}">
|
||||
<div class="form-group" ng-class="{'has-error': adminForm['admin[statistic_profile_attributes][gender]'].$dirty && adminForm['admin[statistic_profile_attributes][gender]'].$invalid}">
|
||||
<label class="checkbox-inline btn btn-default">
|
||||
<input type="radio"
|
||||
name="admin[profile_attributes][gender]"
|
||||
ng-model="admin.profile_attributes.gender"
|
||||
name="admin[statistic_profile_attributes][gender]"
|
||||
ng-model="admin.statistic_profile_attributes.gender"
|
||||
ng-value="true"
|
||||
required/>
|
||||
<i class="fa fa-male m-l-sm"></i> {{ 'man' | translate }}
|
||||
</label>
|
||||
<label class="checkbox-inline btn btn-default">
|
||||
<input type="radio"
|
||||
name="admin[profile_attributes][gender]"
|
||||
ng-model="admin.profile_attributes.gender"
|
||||
name="admin[statistic_profile_attributes][gender]"
|
||||
ng-model="admin.statistic_profile_attributes.gender"
|
||||
ng-value="false"/>
|
||||
<i class="fa fa-female m-l-sm"></i> {{ 'woman' | translate }}
|
||||
</label>
|
||||
@ -73,13 +73,13 @@
|
||||
<span class="help-block" ng-show="adminForm['admin[email]'].$dirty && adminForm['admin[email]'].$error.required" translate>{{ 'email_is_required' }}</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-class="{'has-error': adminForm['admin[profile_attributes][birthday]'].$dirty && adminForm['admin[profile_attributes][birthday]'].$invalid}">
|
||||
<div class="form-group" ng-class="{'has-error': adminForm['admin[statistic_profile_attributes][birthday]'].$dirty && adminForm['admin[statistic_profile_attributes][birthday]'].$invalid}">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon"><i class="fa fa-calendar-o"></i> </span>
|
||||
<input type="text"
|
||||
id="user_birthday"
|
||||
class="form-control"
|
||||
ng-model="admin.profile_attributes.birthday"
|
||||
ng-model="admin.statistic_profile_attributes.birthday"
|
||||
uib-datepicker-popup="{{datePicker.format}}"
|
||||
datepicker-options="datePicker.options"
|
||||
is-open="datePicker.opened"
|
||||
@ -87,8 +87,8 @@
|
||||
ng-click="openDatePicker($event)"
|
||||
/>
|
||||
<input type="hidden"
|
||||
name="admin[profile_attributes][birthday]"
|
||||
value="{{admin.profile_attributes.birthday | toIsoDate}}" />
|
||||
name="admin[statistic_profile_attributes][birthday]"
|
||||
value="{{admin.statistic_profile_attributes.birthday | toIsoDate}}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
<input name="_method" type="hidden" ng-value="method">
|
||||
<input name="user[profile_attributes][id]" type="hidden" ng-value="user.profile.id">
|
||||
<input name="user[invoicing_profile_attributes][id]" type="hidden" ng-value="user.invoicing_profile.id">
|
||||
<input name="user[statistic_profile_attributes][id]" type="hidden" ng-value="user.statistic_profile.id">
|
||||
|
||||
<div class="row m-t">
|
||||
<div class="col-sm-3 col-sm-offset-1">
|
||||
@ -38,27 +39,27 @@
|
||||
</div>
|
||||
<div class="col-sm-offset-1 col-sm-6">
|
||||
|
||||
<div class="form-group" ng-class="{'has-error': userForm['user[profile_attributes][gender]'].$dirty && userForm['user[profile_attributes][gender]'].$invalid}">
|
||||
<div class="form-group" ng-class="{'has-error': userForm['user[statistic_profile_attributes][gender]'].$dirty && userForm['user[statistic_profile_attributes][gender]'].$invalid}">
|
||||
<label class="checkbox-inline btn btn-default">
|
||||
<input type="radio"
|
||||
name="user[profile_attributes][gender]"
|
||||
ng-model="user.profile.gender"
|
||||
name="user[statistic_profile_attributes][gender]"
|
||||
ng-model="user.statistic_profile.gender"
|
||||
value="true"
|
||||
ng-disabled="preventField['profile.gender'] && user.profile.gender && !userForm['user[profile_attributes][gender]'].$dirty"
|
||||
ng-disabled="preventField['profile.gender'] && user.statistic_profile.gender && !userForm['user[statistic_profile_attributes][gender]'].$dirty"
|
||||
required/>
|
||||
<i class="fa fa-male m-l-sm"></i> {{ 'man' | translate }}
|
||||
</label>
|
||||
<label class="checkbox-inline btn btn-default">
|
||||
<input type="radio"
|
||||
name="user[profile_attributes][gender]"
|
||||
ng-model="user.profile.gender"
|
||||
name="user[statistic_profile_attributes][gender]"
|
||||
ng-model="user.statistic_profile.gender"
|
||||
value="false"
|
||||
ng-disabled="preventField['profile.gender'] && user.profile.gender && !userForm['user[profile_attributes][gender]'].$dirty"/>
|
||||
ng-disabled="preventField['profile.gender'] && user.statistic_profile.gender && !userForm['user[statistic_profile_attributes][gender]'].$dirty"/>
|
||||
<i class="fa fa-female m-l-sm"></i> {{ 'woman' | translate }}
|
||||
</label>
|
||||
<span class="exponent m-l-xs"><i class="fa fa-asterisk" aria-hidden="true"></i></span>
|
||||
|
||||
<span class="help-block" ng-show="userForm['user[profile_attributes][gender]'].$dirty && userForm['user[profile_attributes][gender]'].$error.required" translate>{{ 'gender_is_required' }}</span>
|
||||
<span class="help-block" ng-show="userForm['user[statistic_profile_attributes][gender]'].$dirty && userForm['user[statistic_profile_attributes][gender]'].$error.required" translate>{{ 'gender_is_required' }}</span>
|
||||
</div>
|
||||
|
||||
|
||||
@ -200,25 +201,25 @@
|
||||
<span class="help-block" ng-show="userForm['user[invoicing_profile_attributes][organization_attributes][address_attributes][address]'].$dirty && userForm['user[invoicing_profile_attributes][organization_attributes][address_attributes][address]'].$error.required" translate>{{ 'organization_address_is_required' }}</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-class="{'has-error': userForm['user[profile_attributes][birthday]'].$dirty && userForm['user[profile_attributes][birthday]'].$invalid}">
|
||||
<div class="form-group" ng-class="{'has-error': userForm['user[statistic_profile_attributes][birthday]'].$dirty && userForm['user[statistic_profile_attributes][birthday]'].$invalid}">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon"><i class="fa fa-calendar-o"></i> <span class="exponent"><i class="fa fa-asterisk" aria-hidden="true"></i></span></span>
|
||||
<input type="text"
|
||||
id="user_birthday"
|
||||
class="form-control"
|
||||
ng-model="user.profile.birthday"
|
||||
ng-model="user.statistic_profile.birthday"
|
||||
uib-datepicker-popup="{{datePicker.format}}"
|
||||
datepicker-options="datePicker.options"
|
||||
is-open="datePicker.opened"
|
||||
placeholder="{{ 'date_of_birth' | translate }}"
|
||||
ng-click="openDatePicker($event)"
|
||||
ng-disabled="preventField['profile.birthday'] && user.profile.birthday && !userForm['user[profile_attributes][birthday]'].$dirty"
|
||||
ng-disabled="preventField['profile.birthday'] && user.statistic_profile.birthday && !userForm['user[statistic_profile_attributes][birthday]'].$dirty"
|
||||
required/>
|
||||
<input type="hidden"
|
||||
name="user[profile_attributes][birthday]"
|
||||
value="{{user.profile.birthday | toIsoDate}}" />
|
||||
name="user[statistic_profile_attributes][birthday]"
|
||||
value="{{user.statistic_profile.birthday | toIsoDate}}" />
|
||||
</div>
|
||||
<span class="help-block" ng-show="userForm['user[profile_attributes][birthday]'].$dirty && userForm['user[profile_attributes][birthday]'].$error.required" translate>{{ 'date_of_birth_is_required' }}</span>
|
||||
<span class="help-block" ng-show="userForm['user[statistic_profile_attributes][birthday]'].$dirty && userForm['user[statistic_profile_attributes][birthday]'].$error.required" translate>{{ 'date_of_birth_is_required' }}</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
|
@ -12,14 +12,14 @@
|
||||
<label class="checkbox-inline">
|
||||
<input type="radio"
|
||||
name="gender"
|
||||
ng-model="user.profile_attributes.gender"
|
||||
ng-model="user.statistic_profile_attributes.gender"
|
||||
value="true"
|
||||
required/> {{ 'man' | translate }}
|
||||
</label>
|
||||
<label class="checkbox-inline">
|
||||
<input type="radio"
|
||||
name="gender"
|
||||
ng-model="user.profile_attributes.gender"
|
||||
ng-model="user.statistic_profile_attributes.gender"
|
||||
value="false"/> {{ 'woman' | translate }}
|
||||
</label>
|
||||
<span class="exponent m-l-xs"><i class="fa fa-asterisk" aria-hidden="true"></i></span>
|
||||
@ -182,7 +182,7 @@
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
name="birthday"
|
||||
ng-model="user.profile_attributes.birthday"
|
||||
ng-model="user.statistic_profile_attributes.birthday"
|
||||
uib-datepicker-popup="{{datePicker.format}}"
|
||||
datepicker-options="datePicker.options"
|
||||
is-open="datePicker.opened"
|
||||
|
@ -11,24 +11,13 @@ class API::AdminsController < API::ApiController
|
||||
|
||||
def create
|
||||
authorize :admin
|
||||
generated_password = Devise.friendly_token.first(8)
|
||||
@admin = User.new(admin_params.merge(password: generated_password))
|
||||
@admin.send :set_slug
|
||||
res = UserService.create_admin(admin_params)
|
||||
|
||||
# we associate the admin group to prevent linking any other 'normal' group (which won't be deletable afterwards)
|
||||
@admin.group = Group.find_by(slug: 'admins')
|
||||
|
||||
# if the authentication is made through an SSO, generate a migration token
|
||||
@admin.generate_auth_migration_token unless AuthProvider.active.providable_type == DatabaseProvider.name
|
||||
|
||||
if @admin.save(validate: false)
|
||||
@admin.send_confirmation_instructions
|
||||
@admin.add_role(:admin)
|
||||
@admin.remove_role(:member)
|
||||
UsersMailer.delay.notify_user_account_created(@admin, generated_password)
|
||||
if res[:saved]
|
||||
@admin = res[:user]
|
||||
render :create, status: :created
|
||||
else
|
||||
render json: @admin.errors.full_messages, status: :unprocessable_entity
|
||||
render json: res[:user].errors.full_messages, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
@ -47,8 +36,9 @@ class API::AdminsController < API::ApiController
|
||||
def admin_params
|
||||
params.require(:admin).permit(
|
||||
:username, :email,
|
||||
profile_attributes: %i[first_name last_name gender birthday phone],
|
||||
invoicing_profile_attributes: [address_attributes: [:address]]
|
||||
profile_attributes: %i[first_name last_name phone],
|
||||
invoicing_profile_attributes: [address_attributes: [:address]],
|
||||
statistic_profile_attributes: %i[gender birthday]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
@ -189,32 +189,31 @@ class API::MembersController < API::ApiController
|
||||
|
||||
def user_params
|
||||
if current_user.id == params[:id].to_i
|
||||
params.require(:user).permit(:username, :email, :password, :password_confirmation, :group_id, :is_allow_contact,
|
||||
:is_allow_newsletter,
|
||||
profile_attributes: [:id, :first_name, :last_name, :gender, :birthday, :phone, :interest,
|
||||
:software_mastered, :website, :job, :facebook, :twitter,
|
||||
:google_plus, :viadeo, :linkedin, :instagram, :youtube, :vimeo,
|
||||
:dailymotion, :github, :echosciences, :pinterest, :lastfm, :flickr,
|
||||
user_avatar_attributes: %i[id attachment destroy]],
|
||||
invoicing_profile_attributes: [
|
||||
address_attributes: %i[id address],
|
||||
organization_attributes: [:id, :name, address_attributes: %i[id address]]
|
||||
])
|
||||
|
||||
elsif current_user.admin?
|
||||
params.require(:user).permit(:username, :email, :password, :password_confirmation,
|
||||
:is_allow_contact, :is_allow_newsletter, :group_id,
|
||||
training_ids: [], tag_ids: [],
|
||||
profile_attributes: [:id, :first_name, :last_name, :gender, :birthday, :phone, :interest,
|
||||
:software_mastered, :website, :job, :facebook, :twitter,
|
||||
:google_plus, :viadeo, :linkedin, :instagram, :youtube, :vimeo,
|
||||
params.require(:user).permit(:username, :email, :password, :password_confirmation, :group_id, :is_allow_contact, :is_allow_newsletter,
|
||||
profile_attributes: [:id, :first_name, :last_name, :phone, :interest, :software_mastered, :website, :job,
|
||||
:facebook, :twitter, :google_plus, :viadeo, :linkedin, :instagram, :youtube, :vimeo,
|
||||
:dailymotion, :github, :echosciences, :pinterest, :lastfm, :flickr,
|
||||
user_avatar_attributes: %i[id attachment destroy]],
|
||||
invoicing_profile_attributes: [
|
||||
:id,
|
||||
address_attributes: %i[id address],
|
||||
organization_attributes: [:id, :name, address_attributes: %i[id address]]
|
||||
])
|
||||
],
|
||||
statistic_profile_attributes: %i[id gender birthday])
|
||||
|
||||
elsif current_user.admin?
|
||||
params.require(:user).permit(:username, :email, :password, :password_confirmation, :is_allow_contact, :is_allow_newsletter, :group_id,
|
||||
training_ids: [], tag_ids: [],
|
||||
profile_attributes: [:id, :first_name, :last_name, :phone, :interest, :software_mastered, :website, :job,
|
||||
:facebook, :twitter, :google_plus, :viadeo, :linkedin, :instagram, :youtube, :vimeo,
|
||||
:dailymotion, :github, :echosciences, :pinterest, :lastfm, :flickr,
|
||||
user_avatar_attributes: %i[id attachment destroy]],
|
||||
invoicing_profile_attributes: [
|
||||
:id,
|
||||
address_attributes: %i[id address],
|
||||
organization_attributes: [:id, :name, address_attributes: %i[id address]]
|
||||
],
|
||||
statistic_profile_attributes: %i[id gender birthday])
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -23,7 +23,7 @@ class API::ReservationsController < API::ApiController
|
||||
|
||||
def create
|
||||
method = current_user.admin? ? :local : :stripe
|
||||
user_id = current_user.admin? ? reservation_params[:user_id] : current_user.id
|
||||
user_id = current_user.admin? ? params[:reservation][:user_id] : current_user.id
|
||||
|
||||
@reservation = Reservation.new(reservation_params)
|
||||
is_reserve = Reservations::Reserve.new(user_id, current_user.id)
|
||||
@ -56,8 +56,7 @@ class API::ReservationsController < API::ApiController
|
||||
end
|
||||
|
||||
def reservation_params
|
||||
params.require(:reservation).permit(:user_id, :message, :reservable_id, :reservable_type, :card_token, :plan_id,
|
||||
:nb_reserve_places,
|
||||
params.require(:reservation).permit(:message, :reservable_id, :reservable_type, :card_token, :plan_id, :nb_reserve_places,
|
||||
tickets_attributes: %i[event_price_category_id booked],
|
||||
slots_attributes: %i[id start_at end_at availability_id offered])
|
||||
end
|
||||
|
@ -16,10 +16,10 @@ class API::SubscriptionsController < API::ApiController
|
||||
head 403
|
||||
else
|
||||
method = current_user.admin? ? :local : :stripe
|
||||
user_id = current_user.admin? ? subscription_params[:user_id] : current_user.id
|
||||
user_id = current_user.admin? ? params[:subscription][:user_id] : current_user.id
|
||||
|
||||
@subscription = Subscription.new(subscription_params)
|
||||
is_subscribe = Subscriptions::Subscribe.new(user_id, current_user.id)
|
||||
is_subscribe = Subscriptions::Subscribe.new(current_user.id, user_id)
|
||||
.pay_and_save(@subscription, method, coupon_params[:coupon_code], true)
|
||||
|
||||
if is_subscribe
|
||||
@ -35,7 +35,7 @@ class API::SubscriptionsController < API::ApiController
|
||||
|
||||
free_days = params[:subscription][:free] || false
|
||||
|
||||
res = Subscriptions::Subscribe.new(@subscription.user_id, current_user.id)
|
||||
res = Subscriptions::Subscribe.new(current_user.id)
|
||||
.extend_subscription(@subscription, subscription_update_params[:expired_at], free_days)
|
||||
if res.is_a?(Subscription)
|
||||
@subscription = res
|
||||
@ -56,7 +56,7 @@ class API::SubscriptionsController < API::ApiController
|
||||
|
||||
# Never trust parameters from the scary internet, only allow the white list through.
|
||||
def subscription_params
|
||||
params.require(:subscription).permit(:plan_id, :user_id, :card_token)
|
||||
params.require(:subscription).permit(:plan_id, :card_token)
|
||||
end
|
||||
|
||||
def coupon_params
|
||||
|
@ -14,24 +14,13 @@ class API::UsersController < API::ApiController
|
||||
|
||||
def create
|
||||
if current_user.admin?
|
||||
generated_password = Devise.friendly_token.first(8)
|
||||
@user = User.new(email: partner_params[:email],
|
||||
username: "#{partner_params[:first_name]}#{partner_params[:last_name]}",
|
||||
password: generated_password,
|
||||
password_confirmation: generated_password,
|
||||
group_id: Group.first.id)
|
||||
@user.build_profile(first_name: partner_params[:first_name],
|
||||
last_name: partner_params[:last_name],
|
||||
gender: true,
|
||||
birthday: Time.now,
|
||||
phone: '0000000000')
|
||||
res = UserService.create_partner(partner_params)
|
||||
|
||||
if @user.save
|
||||
@user.remove_role :member
|
||||
@user.add_role :partner
|
||||
if res[:saved]
|
||||
@user = res[:user]
|
||||
render status: :created
|
||||
else
|
||||
render json: @user.errors.full_messages, status: :unprocessable_entity
|
||||
render json: res[:user].errors.full_messages, status: :unprocessable_entity
|
||||
end
|
||||
else
|
||||
head 403
|
||||
|
@ -33,10 +33,11 @@ class ApplicationController < ActionController::Base
|
||||
devise_parameter_sanitizer.permit(:sign_up,
|
||||
keys: [
|
||||
{
|
||||
profile_attributes: %i[phone last_name first_name gender birthday interest software_mastered],
|
||||
profile_attributes: %i[phone last_name first_name interest software_mastered],
|
||||
invoicing_profile_attributes: [
|
||||
organization_attributes: [:name, address_attributes: [:address]]
|
||||
]
|
||||
],
|
||||
statistic_profile_attributes: %i[gender birthday]
|
||||
},
|
||||
:username, :is_allow_contact, :is_allow_newsletter, :cgu, :group_id
|
||||
])
|
||||
|
@ -1,5 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Handling a new user registration through the sign-up modal
|
||||
class RegistrationsController < Devise::RegistrationsController
|
||||
# POST /resource
|
||||
# POST /users.json
|
||||
def create
|
||||
build_resource(sign_up_params)
|
||||
|
||||
@ -24,5 +27,4 @@ class RegistrationsController < Devise::RegistrationsController
|
||||
respond_with resource
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,5 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Devise controller for handling client sessions
|
||||
class SessionsController < Devise::SessionsController
|
||||
#before_action :set_csrf_headers, only: [:create, :destroy]
|
||||
|
||||
def new
|
||||
active_provider = AuthProvider.active
|
||||
@ -9,9 +11,4 @@ class SessionsController < Devise::SessionsController
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
def set_csrf_headers
|
||||
cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
|
||||
end
|
||||
end
|
||||
|
3
app/exceptions/no_profile_error.rb
Normal file
3
app/exceptions/no_profile_error.rb
Normal file
@ -0,0 +1,3 @@
|
||||
# Raised when an expected profile (statistic, invoicing or normal) was not found on an user
|
||||
class NoProfileError < StandardError
|
||||
end
|
@ -1,6 +1,7 @@
|
||||
class Group < ActiveRecord::Base
|
||||
has_many :plans
|
||||
has_many :users
|
||||
has_many :statistic_profiles
|
||||
has_many :trainings_pricings, dependent: :destroy
|
||||
has_many :machines_prices, -> { where(priceable_type: 'Machine') }, class_name: 'Price', dependent: :destroy
|
||||
has_many :spaces_prices, -> { where(priceable_type: 'Space') }, class_name: 'Price', dependent: :destroy
|
||||
|
@ -1,3 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# This table will save the user's profile data needed for legal accounting (invoices, wallet, etc.)
|
||||
# Legal accounting must be kept for 10 years but GDPR requires that an user can delete his account at any time.
|
||||
# The data will be kept even if the user is deleted, but it will be unlinked from the user's account.
|
||||
class InvoicingProfile < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
has_one :address, as: :placeable, dependent: :destroy
|
||||
@ -11,17 +16,8 @@ class InvoicingProfile < ActiveRecord::Base
|
||||
|
||||
has_many :history_values, dependent: :nullify
|
||||
|
||||
after_create :create_a_wallet
|
||||
|
||||
|
||||
def full_name
|
||||
# if first_name or last_name is nil, the empty string will be used as a temporary replacement
|
||||
(first_name || '').humanize.titleize + ' ' + (last_name || '').humanize.titleize
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_a_wallet
|
||||
create_wallet
|
||||
end
|
||||
end
|
||||
|
@ -10,11 +10,9 @@ class Profile < ActiveRecord::Base
|
||||
|
||||
validates :first_name, presence: true, length: { maximum: 30 }
|
||||
validates :last_name, presence: true, length: { maximum: 30 }
|
||||
validates :gender, inclusion: { in: [true, false] }
|
||||
validates :birthday, presence: true
|
||||
validates_numericality_of :phone, only_integer: true, allow_blank: false
|
||||
|
||||
after_save :update_invoicing_profile
|
||||
after_commit :update_invoicing_profile, if: :invoicing_data_was_modified?, on: [:update]
|
||||
|
||||
def full_name
|
||||
# if first_name or last_name is nil, the empty string will be used as a temporary replacement
|
||||
@ -25,19 +23,6 @@ class Profile < ActiveRecord::Base
|
||||
full_name
|
||||
end
|
||||
|
||||
def age
|
||||
if birthday.present?
|
||||
now = Time.now.utc.to_date
|
||||
(now - birthday).to_f / 365.2425
|
||||
else
|
||||
''
|
||||
end
|
||||
end
|
||||
|
||||
def str_gender
|
||||
gender ? 'male' : 'female'
|
||||
end
|
||||
|
||||
def self.mapping
|
||||
# we protect some fields as they are designed to be managed by the system and must not be updated externally
|
||||
blacklist = %w[id user_id created_at updated_at]
|
||||
@ -51,19 +36,17 @@ class Profile < ActiveRecord::Base
|
||||
|
||||
private
|
||||
|
||||
def invoicing_data_was_modified?
|
||||
first_name_changed? or last_name_changed? or new_record?
|
||||
end
|
||||
|
||||
def update_invoicing_profile
|
||||
if user.invoicing_profile.nil?
|
||||
InvoicingProfile.create!(
|
||||
user: user,
|
||||
first_name: first_name,
|
||||
last_name: last_name
|
||||
)
|
||||
else
|
||||
user.invoicing_profile.update_attributes(
|
||||
first_name: first_name,
|
||||
last_name: last_name
|
||||
)
|
||||
end
|
||||
raise NoProfileError if user.invoicing_profile.nil?
|
||||
|
||||
user.invoicing_profile.update_attributes(
|
||||
first_name: first_name,
|
||||
last_name: last_name
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,7 +1,7 @@
|
||||
class Reservation < ActiveRecord::Base
|
||||
include NotifyWith::NotificationAttachedObject
|
||||
|
||||
belongs_to :user
|
||||
belongs_to :statistic_profile
|
||||
|
||||
has_many :slots_reservations, dependent: :destroy
|
||||
has_many :slots, through: :slots_reservations
|
||||
@ -240,8 +240,8 @@ class Reservation < ActiveRecord::Base
|
||||
# TODO: refactoring
|
||||
customer = Stripe::Customer.retrieve(user.stp_customer_id)
|
||||
if plan_id
|
||||
self.subscription = Subscription.find_or_initialize_by(user_id: user.id)
|
||||
subscription.attributes = { plan_id: plan_id, user_id: user.id, card_token: card_token, expiration_date: nil }
|
||||
self.subscription = Subscription.find_or_initialize_by(statistic_profile_id: statistic_profile_id)
|
||||
subscription.attributes = { plan_id: plan_id, statistic_profile_id: statistic_profile_id, card_token: card_token, expiration_date: nil }
|
||||
if subscription.save_with_payment(operator_id, false)
|
||||
self.stp_invoice_id = invoice_items.first.refresh.invoice
|
||||
invoice.stp_invoice_id = invoice_items.first.refresh.invoice
|
||||
@ -338,8 +338,8 @@ class Reservation < ActiveRecord::Base
|
||||
end
|
||||
|
||||
# check reservation amount total and strip invoice total to pay is equal
|
||||
# @params stp_invoice[Stripe::Invoice]
|
||||
# @params coupon_code[String]
|
||||
# @param stp_invoice[Stripe::Invoice]
|
||||
# @param coupon_code[String]
|
||||
# return Boolean
|
||||
def is_equal_reservation_total_and_stp_invoice_total(stp_invoice, coupon_code = nil)
|
||||
compute_amount_total_to_pay(coupon_code) == stp_invoice.total
|
||||
@ -375,8 +375,8 @@ class Reservation < ActiveRecord::Base
|
||||
return false unless valid?
|
||||
|
||||
if plan_id
|
||||
self.subscription = Subscription.find_or_initialize_by(user_id: user.id)
|
||||
subscription.attributes = { plan_id: plan_id, user_id: user.id, expiration_date: nil }
|
||||
self.subscription = Subscription.find_or_initialize_by(statistic_profile_id: statistic_profile_id)
|
||||
subscription.attributes = { plan_id: plan_id, statistic_profile_id: statistic_profile_id, expiration_date: nil }
|
||||
if subscription.save_with_local_payment(operator_id, false)
|
||||
invoice.invoice_items.push InvoiceItem.new(
|
||||
amount: subscription.plan.amount,
|
||||
@ -405,6 +405,10 @@ class Reservation < ActiveRecord::Base
|
||||
total
|
||||
end
|
||||
|
||||
def user
|
||||
statistic_profile.user
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def machine_not_already_reserved
|
||||
|
31
app/models/statistic_profile.rb
Normal file
31
app/models/statistic_profile.rb
Normal file
@ -0,0 +1,31 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# This table will save the user's profile data needed for statistical purposes.
|
||||
# GDPR requires that an user can delete his account at any time but we need to keep the statistics original data to being able to
|
||||
# rebuild them at any time.
|
||||
# The data will be kept even if the user is deleted, but it will be unlinked from the user's account (ie. anonymized)
|
||||
class StatisticProfile < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
belongs_to :group
|
||||
|
||||
# relations to reservations, trainings, subscriptions
|
||||
has_many :subscriptions, dependent: :destroy
|
||||
accepts_nested_attributes_for :subscriptions, allow_destroy: false
|
||||
|
||||
has_many :reservations, dependent: :destroy
|
||||
accepts_nested_attributes_for :reservations, allow_destroy: false
|
||||
|
||||
def str_gender
|
||||
gender ? 'male' : 'female'
|
||||
end
|
||||
|
||||
def age
|
||||
if birthday.present?
|
||||
now = Time.now.utc.to_date
|
||||
(now - birthday).to_f / 365.2425
|
||||
else
|
||||
''
|
||||
end
|
||||
end
|
||||
|
||||
end
|
@ -2,7 +2,7 @@ class Subscription < ActiveRecord::Base
|
||||
include NotifyWith::NotificationAttachedObject
|
||||
|
||||
belongs_to :plan
|
||||
belongs_to :user
|
||||
belongs_to :statistic_profile
|
||||
|
||||
has_many :invoices, as: :invoiced, dependent: :destroy
|
||||
has_many :offer_days, dependent: :destroy
|
||||
@ -223,6 +223,10 @@ class Subscription < ActiveRecord::Base
|
||||
false
|
||||
end
|
||||
|
||||
def user
|
||||
statistic_profile.user
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def notify_member_subscribed_plan
|
||||
|
@ -24,22 +24,19 @@ class User < ActiveRecord::Base
|
||||
has_one :invoicing_profile, dependent: :nullify
|
||||
accepts_nested_attributes_for :invoicing_profile
|
||||
|
||||
has_one :statistic_profile, dependent: :nullify
|
||||
accepts_nested_attributes_for :statistic_profile
|
||||
|
||||
has_many :my_projects, foreign_key: :author_id, class_name: 'Project', dependent: :destroy
|
||||
has_many :project_users, dependent: :destroy
|
||||
has_many :projects, through: :project_users
|
||||
|
||||
has_many :reservations, dependent: :destroy
|
||||
accepts_nested_attributes_for :reservations, allow_destroy: true
|
||||
|
||||
# Trainings that were already passed
|
||||
has_many :user_trainings, dependent: :destroy
|
||||
has_many :trainings, through: :user_trainings
|
||||
|
||||
belongs_to :group
|
||||
|
||||
has_many :subscriptions, dependent: :destroy
|
||||
accepts_nested_attributes_for :subscriptions, allow_destroy: true
|
||||
|
||||
has_many :users_credits, dependent: :destroy
|
||||
has_many :credits, through: :users_credits
|
||||
|
||||
@ -62,20 +59,27 @@ class User < ActiveRecord::Base
|
||||
before_create :assign_default_role
|
||||
after_commit :create_stripe_customer, on: [:create]
|
||||
after_commit :notify_admin_when_user_is_created, on: :create
|
||||
after_create :init_dependencies
|
||||
after_update :notify_group_changed, if: :group_id_changed?
|
||||
after_save :update_invoicing_profile
|
||||
after_update :update_invoicing_profile, if: :invoicing_data_was_modified?
|
||||
after_update :update_statistic_profile, if: :statistic_data_was_modified?
|
||||
|
||||
attr_accessor :cgu
|
||||
delegate :first_name, to: :profile
|
||||
delegate :last_name, to: :profile
|
||||
delegate :subscriptions, to: :statistic_profile
|
||||
delegate :reservations, to: :statistic_profile
|
||||
delegate :wallet, to: :invoicing_profile
|
||||
delegate :wallet_transactions, to: :invoicing_profile
|
||||
delegate :invoices, to: :invoicing_profile
|
||||
|
||||
validate :cgu_must_accept, if: :new_record?
|
||||
|
||||
validates :username, presence: true, uniqueness: true, length: { maximum: 30 }
|
||||
|
||||
scope :active, -> { where(is_active: true) }
|
||||
scope :without_subscription, -> { includes(:subscriptions).where(subscriptions: { user_id: nil }) }
|
||||
scope :with_subscription, -> { joins(:subscriptions) }
|
||||
scope :without_subscription, -> { includes(statistic_profile: [:subscriptions]).where(subscriptions: { statistic_profile_id: nil }) }
|
||||
scope :with_subscription, -> { joins(statistic_profile: [:subscriptions]) }
|
||||
|
||||
def to_json(*)
|
||||
ApplicationController.new.view_context.render(
|
||||
@ -128,18 +132,6 @@ class User < ActiveRecord::Base
|
||||
my_projects.to_a.concat projects
|
||||
end
|
||||
|
||||
def invoices
|
||||
invoicing_profile.invoices
|
||||
end
|
||||
|
||||
def wallet
|
||||
invoicing_profile.wallet
|
||||
end
|
||||
|
||||
def wallet_transactions
|
||||
invoicing_profile.wallet_transactions
|
||||
end
|
||||
|
||||
def generate_subscription_invoice(operator_id)
|
||||
return unless subscription
|
||||
|
||||
@ -166,9 +158,7 @@ class User < ActiveRecord::Base
|
||||
|
||||
def self.from_omniauth(auth)
|
||||
active_provider = AuthProvider.active
|
||||
if active_provider.strategy_name != auth.provider
|
||||
raise SecurityError, 'The identity provider does not match the activated one'
|
||||
end
|
||||
raise SecurityError, 'The identity provider does not match the activated one' if active_provider.strategy_name != auth.provider
|
||||
|
||||
where(provider: auth.provider, uid: auth.uid).first_or_create.tap do |user|
|
||||
# execute this regardless of whether record exists or not (-> User#tap)
|
||||
@ -182,8 +172,8 @@ class User < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def need_completion?
|
||||
profile.gender.nil? || profile.first_name.blank? || profile.last_name.blank? || username.blank? ||
|
||||
email.blank? || encrypted_password.blank? || group_id.nil? || profile.birthday.blank? || profile.phone.blank?
|
||||
statistic_profile.gender.nil? || profile.first_name.blank? || profile.last_name.blank? || username.blank? ||
|
||||
email.blank? || encrypted_password.blank? || group_id.nil? || statistic_profile.birthday.blank? || profile.phone.blank?
|
||||
end
|
||||
|
||||
## Retrieve the requested data in the User and user's Profile tables
|
||||
@ -244,9 +234,7 @@ class User < ActiveRecord::Base
|
||||
## and remove the auth_token to mark his account as "migrated"
|
||||
def link_with_omniauth_provider(auth)
|
||||
active_provider = AuthProvider.active
|
||||
if active_provider.strategy_name != auth.provider
|
||||
raise SecurityError, 'The identity provider does not match the activated one'
|
||||
end
|
||||
raise SecurityError, 'The identity provider does not match the activated one' if active_provider.strategy_name != auth.provider
|
||||
|
||||
if User.where(provider: auth.provider, uid: auth.uid).size.positive?
|
||||
raise DuplicateIndexError, "This #{active_provider.name} account is already linked to an existing user"
|
||||
@ -362,16 +350,52 @@ class User < ActiveRecord::Base
|
||||
attached_object: self
|
||||
end
|
||||
|
||||
def update_invoicing_profile
|
||||
def invoicing_data_was_modified?
|
||||
email_changed?
|
||||
end
|
||||
|
||||
def statistic_data_was_modified?
|
||||
group_id_changed?
|
||||
end
|
||||
|
||||
def init_dependencies
|
||||
if invoicing_profile.nil?
|
||||
InvoicingProfile.create!(
|
||||
user: user,
|
||||
email: email
|
||||
)
|
||||
else
|
||||
invoicing_profile.update_attributes(
|
||||
email: email
|
||||
ip = InvoicingProfile.create!(
|
||||
user: self,
|
||||
email: email,
|
||||
first_name: first_name,
|
||||
last_name: last_name
|
||||
)
|
||||
end
|
||||
if wallet.nil?
|
||||
ip ||= invoicing_profile
|
||||
Wallet.create!(
|
||||
invoicing_profile: ip
|
||||
)
|
||||
end
|
||||
if statistic_profile.nil?
|
||||
StatisticProfile.create!(
|
||||
user: self,
|
||||
group_id: group_id
|
||||
)
|
||||
else
|
||||
update_statistic_profile
|
||||
end
|
||||
end
|
||||
|
||||
def update_invoicing_profile
|
||||
raise NoProfileError if invoicing_profile.nil?
|
||||
|
||||
invoicing_profile.update_attributes(
|
||||
email: email
|
||||
)
|
||||
end
|
||||
|
||||
def update_statistic_profile
|
||||
raise NoProfileError if statistic_profile.nil?
|
||||
|
||||
statistic_profile.update_attributes(
|
||||
group_id: group_id
|
||||
)
|
||||
end
|
||||
end
|
||||
|
@ -2,7 +2,7 @@ class UserPolicy < ApplicationPolicy
|
||||
class Scope < Scope
|
||||
def resolve
|
||||
if user.admin?
|
||||
scope.includes(:group, :training_credits, :machine_credits, subscriptions: [plan: [:credits]], profile: [:user_avatar])
|
||||
scope.includes(:group, :training_credits, :machine_credits, statistic_profile: [subscriptions: [plan: [:credits]]], profile: [:user_avatar])
|
||||
.joins(:roles).where("users.is_active = 'true' AND roles.name = 'member'").order('users.created_at desc')
|
||||
else
|
||||
scope.includes(profile: [:user_avatar]).joins(:roles).where("users.is_active = 'true' AND roles.name = 'member'")
|
||||
|
@ -93,7 +93,7 @@ class Availabilities::AvailabilitiesService
|
||||
|
||||
def reservations(reservable)
|
||||
Reservation.where('reservable_type = ? and reservable_id = ?', reservable.class.name, reservable.id)
|
||||
.includes(:slots, user: [:profile])
|
||||
.includes(:slots, statistic_profile: [user: [:profile]])
|
||||
.references(:slots, :user)
|
||||
.where('slots.start_at > ?', Time.now)
|
||||
end
|
||||
|
@ -4,16 +4,25 @@
|
||||
class Members::ListService
|
||||
class << self
|
||||
def list(params)
|
||||
@query = User.includes(:profile, :group, :subscriptions)
|
||||
@query = User.includes(:profile, :group, :statistic_profile)
|
||||
.joins(:profile,
|
||||
:statistic_profile,
|
||||
:group,
|
||||
:roles,
|
||||
'LEFT JOIN "subscriptions" ON "subscriptions"."user_id" = "users"."id" ' \
|
||||
'LEFT JOIN (
|
||||
SELECT *
|
||||
FROM "subscriptions" AS s1
|
||||
INNER JOIN (
|
||||
SELECT MAX("created_at") AS "s2_created_at", "statistic_profile_id" AS "s2_statistic_profile_id"
|
||||
FROM "subscriptions"
|
||||
GROUP BY "statistic_profile_id"
|
||||
) As s2
|
||||
ON "s1"."statistic_profile_id" = "s2"."s2_statistic_profile_id"
|
||||
WHERE "s1"."expiration_date" > now()::date
|
||||
) AS "subscriptions" ON "subscriptions"."statistic_profile_id" = "statistic_profiles"."id" ' \
|
||||
'LEFT JOIN "plans" ON "plans"."id" = "subscriptions"."plan_id"')
|
||||
.where("users.is_active = 'true' AND roles.name = 'member'")
|
||||
.order(list_order(params))
|
||||
.page(params[:page])
|
||||
.per(params[:size])
|
||||
|
||||
# ILIKE => PostgreSQL case-insensitive LIKE
|
||||
if params[:search].size.positive?
|
||||
@ -31,12 +40,13 @@ class Members::ListService
|
||||
def search(current_user, query, subscription)
|
||||
members = User.includes(:profile)
|
||||
.joins(:profile,
|
||||
:statistic_profile,
|
||||
:roles,
|
||||
'LEFT JOIN "subscriptions" ON "subscriptions"."user_id" = "users"."id" AND ' \
|
||||
'LEFT JOIN "subscriptions" ON "subscriptions"."statistic_profile_id" = "statistic_profiles"."id" AND ' \
|
||||
'"subscriptions"."created_at" = ( ' \
|
||||
'SELECT max("created_at") ' \
|
||||
'FROM "subscriptions" ' \
|
||||
'WHERE "user_id" = "users"."id")')
|
||||
'WHERE "statistic_profile_id" = "statistic_profiles"."id")')
|
||||
.where("users.is_active = 'true' AND roles.name = 'member'")
|
||||
.limit(50)
|
||||
query.downcase.split(' ').each do |word|
|
||||
@ -64,6 +74,8 @@ class Members::ListService
|
||||
def list_order(params)
|
||||
direction = (params[:order_by][0] == '-' ? 'DESC' : 'ASC')
|
||||
order_key = (params[:order_by][0] == '-' ? params[:order_by][1, params[:order_by].size] : params[:order_by])
|
||||
limit = params[:size]
|
||||
offset = (params[:page]&.to_i || 1) - 1
|
||||
|
||||
order_key = case order_key
|
||||
when 'last_name'
|
||||
@ -82,7 +94,7 @@ class Members::ListService
|
||||
'users.id'
|
||||
end
|
||||
|
||||
"#{order_key} #{direction}"
|
||||
"#{order_key} #{direction} LIMIT #{limit} OFFSET #{offset}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -10,7 +10,7 @@ class Reservations::Reserve
|
||||
end
|
||||
|
||||
def pay_and_save(reservation, payment_method, coupon)
|
||||
reservation.user_id = user_id
|
||||
reservation.statistic_profile_id = User.find(user_id).statistic_profile.id
|
||||
if payment_method == :local
|
||||
reservation.save_with_local_payment(operator_id, coupon)
|
||||
elsif payment_method == :stripe
|
||||
|
@ -356,8 +356,8 @@ class StatisticService
|
||||
def user_info(user)
|
||||
{
|
||||
user_id: user.id,
|
||||
gender: user.profile.str_gender,
|
||||
age: user.profile.age,
|
||||
gender: user.statistic_profile.str_gender,
|
||||
age: user.statistic_profile.age,
|
||||
group: user.group ? user.group.slug : nil,
|
||||
email: user.email
|
||||
}
|
||||
|
@ -4,13 +4,15 @@
|
||||
class Subscriptions::Subscribe
|
||||
attr_accessor :user_id, :operator_id
|
||||
|
||||
def initialize(user_id, operator_id)
|
||||
def initialize(operator_id, user_id = nil)
|
||||
@user_id = user_id
|
||||
@operator_id = operator_id
|
||||
end
|
||||
|
||||
def pay_and_save(subscription, payment_method, coupon, invoice)
|
||||
subscription.user_id = user_id
|
||||
return false if user_id.nil?
|
||||
|
||||
subscription.statistic_profile_id = User.find(user_id).statistic_profile.id
|
||||
if payment_method == :local
|
||||
subscription.save_with_local_payment(operator_id, invoice, coupon)
|
||||
elsif payment_method == :stripe
|
||||
@ -23,7 +25,7 @@ class Subscriptions::Subscribe
|
||||
|
||||
new_sub = Subscription.create(
|
||||
plan_id: subscription.plan_id,
|
||||
user_id: subscription.user_id,
|
||||
statistic_profile_id: subscription.statistic_profile_id,
|
||||
expiration_date: new_expiration_date
|
||||
)
|
||||
if new_sub.save
|
||||
@ -32,4 +34,4 @@ class Subscriptions::Subscribe
|
||||
end
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
53
app/services/user_service.rb
Normal file
53
app/services/user_service.rb
Normal file
@ -0,0 +1,53 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# helpers for managing users with special roles
|
||||
class UserService
|
||||
def self.create_partner(params)
|
||||
generated_password = Devise.friendly_token.first(8)
|
||||
group_id = Group.first.id
|
||||
user = User.new(
|
||||
email: params[:email],
|
||||
username: "#{params[:first_name]}#{params[:last_name]}".parameterize,
|
||||
password: generated_password,
|
||||
password_confirmation: generated_password,
|
||||
group_id: group_id
|
||||
)
|
||||
user.build_profile(
|
||||
first_name: params[:first_name],
|
||||
last_name: params[:last_name],
|
||||
phone: '0000000000'
|
||||
)
|
||||
user.build_statistic_profile(
|
||||
gender: true,
|
||||
birthday: Time.now
|
||||
)
|
||||
|
||||
saved = user.save
|
||||
if saved
|
||||
user.remove_role :member
|
||||
user.add_role :partner
|
||||
end
|
||||
{ saved: saved, user: user }
|
||||
end
|
||||
|
||||
def self.create_admin(params)
|
||||
generated_password = Devise.friendly_token.first(8)
|
||||
admin = User.new(params.merge(password: generated_password))
|
||||
admin.send :set_slug
|
||||
|
||||
# we associate the admin group to prevent linking any other 'normal' group (which won't be deletable afterwards)
|
||||
admin.group = Group.find_by(slug: 'admins')
|
||||
|
||||
# if the authentication is made through an SSO, generate a migration token
|
||||
admin.generate_auth_migration_token unless AuthProvider.active.providable_type == DatabaseProvider.name
|
||||
|
||||
saved = admin.save(validate: false)
|
||||
if saved
|
||||
admin.send_confirmation_instructions
|
||||
admin.add_role(:admin)
|
||||
admin.remove_role(:member)
|
||||
UsersMailer.delay.notify_user_account_created(admin, generated_password)
|
||||
end
|
||||
{ saved: saved, user: admin }
|
||||
end
|
||||
end
|
@ -1,7 +1,7 @@
|
||||
class SubscriptionGroupValidator < ActiveModel::Validator
|
||||
def validate(record)
|
||||
if record.user.group != record.plan.group
|
||||
record.errors[:plan_id] << "This plan is not compatible with the current user's group"
|
||||
end
|
||||
return if record.statistic_profile.group_id == record.plan.group_id
|
||||
|
||||
record.errors[:plan_id] << "This plan is not compatible with the current user's group"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -3,8 +3,8 @@ json.profile_attributes do
|
||||
json.id admin.profile.id
|
||||
json.first_name admin.profile.first_name
|
||||
json.last_name admin.profile.last_name
|
||||
json.gender admin.profile.gender
|
||||
json.birthday admin.profile.birthday if admin.profile.birthday
|
||||
json.gender admin.statistic_profile.gender
|
||||
json.birthday admin.statistic_profile.birthday if admin.statistic_profile.birthday
|
||||
json.phone admin.profile.phone
|
||||
if admin.profile.user_avatar
|
||||
json.user_avatar do
|
||||
|
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
json.extract! member, :id, :username, :email, :group_id
|
||||
json.role member.roles.first.name
|
||||
json.name member.profile.full_name
|
||||
@ -13,8 +15,6 @@ json.profile do
|
||||
end
|
||||
json.first_name member.profile.first_name
|
||||
json.last_name member.profile.last_name
|
||||
json.gender member.profile.gender.to_s
|
||||
json.birthday member.profile.birthday.to_date.iso8601 if member.profile.birthday
|
||||
json.interest member.profile.interest
|
||||
json.software_mastered member.profile.software_mastered
|
||||
json.phone member.profile.phone
|
||||
@ -46,6 +46,12 @@ json.invoicing_profile do
|
||||
end
|
||||
end
|
||||
|
||||
json.statistic_profile do
|
||||
json.id member.statistic_profile.id
|
||||
json.gender member.statistic_profile.gender.to_s
|
||||
json.birthday member.statistic_profile&.birthday&.to_date&.iso8601
|
||||
end
|
||||
|
||||
if member.subscribed_plan
|
||||
json.subscribed_plan do
|
||||
json.partial! 'api/shared/plan', plan: member.subscribed_plan
|
||||
|
@ -1,4 +1,6 @@
|
||||
user_is_admin = (current_user and current_user.admin?)
|
||||
# frozen_string_literal: true
|
||||
|
||||
user_is_admin = current_user&.admin?
|
||||
max_members = @query.except(:offset, :limit, :order).count
|
||||
|
||||
json.array!(@members) do |member|
|
||||
@ -10,55 +12,77 @@ json.array!(@members) do |member|
|
||||
json.email member.email if current_user
|
||||
json.first_name member.profile.first_name
|
||||
json.last_name member.profile.last_name
|
||||
json.profile do
|
||||
json.user_avatar do
|
||||
json.id member.profile.user_avatar.id
|
||||
json.attachment_url member.profile.user_avatar.attachment_url
|
||||
end if member.profile.user_avatar
|
||||
json.first_name member.profile.first_name
|
||||
json.last_name member.profile.last_name
|
||||
json.gender member.profile.gender.to_s
|
||||
if user_is_admin
|
||||
json.phone member.profile.phone
|
||||
json.birthday member.profile.birthday.iso8601 if member.profile.birthday
|
||||
end
|
||||
end if attribute_requested?(@requested_attributes, 'profile')
|
||||
json.need_completion member.need_completion?
|
||||
json.group_id member.group_id
|
||||
json.group do
|
||||
json.id member.group.id
|
||||
json.name member.group.name
|
||||
end if attribute_requested?(@requested_attributes, 'group') and member.group
|
||||
|
||||
if user_is_admin
|
||||
json.subscribed_plan do
|
||||
json.partial! 'api/shared/plan', plan: member.subscribed_plan
|
||||
end if member.subscribed_plan
|
||||
json.subscription do
|
||||
json.id member.subscription.id
|
||||
json.expired_at member.subscription.expired_at.iso8601
|
||||
json.canceled_at member.subscription.canceled_at.iso8601 if member.subscription.canceled_at
|
||||
json.stripe member.subscription.stp_subscription_id.present?
|
||||
json.plan do
|
||||
json.id member.subscription.plan.id
|
||||
json.name member.subscription.plan.name
|
||||
json.interval member.subscription.plan.interval
|
||||
json.amount member.subscription.plan.amount ? (member.subscription.plan.amount / 100.0) : 0
|
||||
if attribute_requested?(@requested_attributes, 'profile')
|
||||
json.profile do
|
||||
if member.profile.user_avatar
|
||||
json.user_avatar do
|
||||
json.id member.profile.user_avatar.id
|
||||
json.attachment_url member.profile.user_avatar.attachment_url
|
||||
end
|
||||
end
|
||||
end if member.subscription
|
||||
end if attribute_requested?(@requested_attributes, 'subscription')
|
||||
json.first_name member.profile.first_name
|
||||
json.last_name member.profile.last_name
|
||||
json.phone member.profile.phone
|
||||
end
|
||||
if user_is_admin
|
||||
json.statistic_profile do
|
||||
json.gender member.statistic_profile.gender.to_s
|
||||
json.birthday member.statistic_profile&.birthday&.iso8601
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
json.training_credits member.training_credits do |tc|
|
||||
json.training_id tc.creditable_id
|
||||
end if attribute_requested?(@requested_attributes, 'credits') or attribute_requested?(@requested_attributes, 'training_credits')
|
||||
if attribute_requested?(@requested_attributes, 'group') && member.group
|
||||
json.group do
|
||||
json.id member.group.id
|
||||
json.name member.group.name
|
||||
end
|
||||
end
|
||||
|
||||
json.machine_credits member.machine_credits do |mc|
|
||||
json.machine_id mc.creditable_id
|
||||
json.hours_used mc.users_credits.find_by(user_id: member.id).hours_used
|
||||
end if attribute_requested?(@requested_attributes, 'credits') or attribute_requested?(@requested_attributes, 'machine_credits')
|
||||
if attribute_requested?(@requested_attributes, 'subscription')
|
||||
if user_is_admin
|
||||
if member.subscribed_plan
|
||||
json.subscribed_plan do
|
||||
json.partial! 'api/shared/plan', plan: member.subscribed_plan
|
||||
end
|
||||
end
|
||||
if member.subscription
|
||||
json.subscription do
|
||||
json.id member.subscription.id
|
||||
json.expired_at member.subscription.expired_at.iso8601
|
||||
json.canceled_at member.subscription&.canceled_at&.iso8601
|
||||
json.stripe member.subscription.stp_subscription_id.present?
|
||||
json.plan do
|
||||
json.id member.subscription.plan.id
|
||||
json.name member.subscription.plan.name
|
||||
json.interval member.subscription.plan.interval
|
||||
json.amount member.subscription.plan.amount ? (member.subscription.plan.amount / 100.0) : 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
json.tags member.tags do |t|
|
||||
json.id t.id
|
||||
json.name t.name
|
||||
end if attribute_requested?(@requested_attributes, 'tags')
|
||||
if attribute_requested?(@requested_attributes, 'credits') || attribute_requested?(@requested_attributes, 'training_credits')
|
||||
json.training_credits member.training_credits do |tc|
|
||||
json.training_id tc.creditable_id
|
||||
end
|
||||
end
|
||||
|
||||
if attribute_requested?(@requested_attributes, 'credits') || attribute_requested?(@requested_attributes, 'machine_credits')
|
||||
json.machine_credits member.machine_credits do |mc|
|
||||
json.machine_id mc.creditable_id
|
||||
json.hours_used mc.users_credits.find_by(user_id: member.id).hours_used
|
||||
end
|
||||
end
|
||||
|
||||
if attribute_requested?(@requested_attributes, 'tags')
|
||||
json.tags member.tags do |t|
|
||||
json.id t.id
|
||||
json.name t.name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -39,13 +39,15 @@ json.all_projects @member.all_projects do |project|
|
||||
json.first_name pu.user.profile.first_name
|
||||
json.last_name pu.user.profile.last_name
|
||||
json.full_name pu.user.profile.full_name
|
||||
json.user_avatar do
|
||||
json.id pu.user.profile.user_avatar.id
|
||||
json.attachment_url pu.user.profile.user_avatar.attachment_url
|
||||
end if pu.user.profile.user_avatar
|
||||
if pu.user.profile.user_avatar
|
||||
json.user_avatar do
|
||||
json.id pu.user.profile.user_avatar.id
|
||||
json.attachment_url pu.user.profile.user_avatar.attachment_url
|
||||
end
|
||||
end
|
||||
json.username pu.user.username
|
||||
json.is_valid pu.is_valid
|
||||
json.valid_token pu.valid_token if !pu.is_valid and @member == pu.user
|
||||
json.valid_token pu.valid_token if !pu.is_valid && @member == pu.user
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -2,6 +2,6 @@ json.title notification.notification_type
|
||||
json.description _t('.user_NAME_changed_his_group_html',
|
||||
{
|
||||
NAME: notification.attached_object.profile.full_name,
|
||||
GENDER: bool_to_sym(notification.attached_object.profile.gender)
|
||||
GENDER: bool_to_sym(notification.attached_object.statistic_profile.gender)
|
||||
}) # messageFormat
|
||||
json.url notification_url(notification, format: :json)
|
||||
|
@ -2,7 +2,7 @@ json.title notification.notification_type
|
||||
json.description _t('.user_NAME_has_merged_his_account_with_the_one_imported_from_PROVIDER_UID_html',
|
||||
{
|
||||
NAME: notification.attached_object.profile.full_name,
|
||||
GENDER: bool_to_sym(notification.attached_object.profile.gender),
|
||||
GENDER: bool_to_sym(notification.attached_object.statistic_profile.gender),
|
||||
PROVIDER: notification.attached_object.provider,
|
||||
UID: notification.attached_object.uid
|
||||
}) # messageFormat
|
||||
|
@ -1,5 +1,5 @@
|
||||
json.id reservation.id
|
||||
json.user_id reservation.user_id
|
||||
json.user_id reservation.statistic_profile.user_id
|
||||
json.user_full_name reservation.user.profile.full_name
|
||||
json.message reservation.message
|
||||
json.slots reservation.slots do |s|
|
||||
|
@ -1,16 +1,18 @@
|
||||
json.id @reservation.id
|
||||
json.user_id @reservation.user_id
|
||||
json.user_id @reservation.statistic_profile.user_id
|
||||
json.user do
|
||||
json.id @reservation.user.id
|
||||
json.subscribed_plan do
|
||||
json.partial! 'api/shared/plan', plan: @reservation.user.subscribed_plan
|
||||
end if @reservation.user.subscribed_plan
|
||||
if @reservation.user.subscribed_plan
|
||||
json.subscribed_plan do
|
||||
json.partial! 'api/shared/plan', plan: @reservation.user.subscribed_plan
|
||||
end
|
||||
end
|
||||
json.training_credits @reservation.user.training_credits do |tc|
|
||||
json.training_id tc.creditable_id
|
||||
end
|
||||
json.machine_credits @reservation.user.machine_credits do |mc|
|
||||
json.machine_id mc.creditable_id
|
||||
json.hours_used mc.users_credits.find_by(user_id: @reservation.user_id).hours_used
|
||||
json.hours_used mc.users_credits.find_by(user_id: @reservation.statistic_profile.user_id).hours_used
|
||||
end
|
||||
end
|
||||
json.message @reservation.message
|
||||
|
@ -1,2 +1,4 @@
|
||||
json.extract! @user, :id, :email, :first_name, :last_name
|
||||
json.name "#{@user.first_name} #{@user.last_name}"
|
||||
# frozen_string_literal: true
|
||||
|
||||
json.extract! @user, :id, :email, :first_name, :last_name
|
||||
json.name @user.profile.full_name
|
||||
|
@ -1,4 +1,4 @@
|
||||
json.users @users do |user|
|
||||
json.extract! user, :id, :email, :first_name, :last_name
|
||||
json.name "#{user.first_name} #{user.last_name}"
|
||||
json.name user.profile.full_name
|
||||
end
|
||||
|
@ -14,10 +14,14 @@ json.invoices do
|
||||
end
|
||||
end
|
||||
json.user do
|
||||
json.extract! invoice[:invoice].user, :id, :email, :created_at
|
||||
json.profile do
|
||||
json.extract! invoice[:invoice].user.profile, :id, :first_name, :last_name, :birthday, :phone
|
||||
json.gender invoice[:invoice].user.profile.gender ? 'male' : 'female'
|
||||
json.extract! invoice[:invoice].invoicing_profile, :user_id, :email, :first_name, :last_name
|
||||
json.address invoice[:invoice].invoicing_profile&.address&.address
|
||||
json.invoicing_profile_id invoice[:invoice].invoicing_profile.id
|
||||
if invoice[:invoice].invoicing_profile.organization
|
||||
json.organization do
|
||||
json.extract! invoice[:invoice].invoicing_profile.organization, :name, :id
|
||||
json.address invoice[:invoice].invoicing_profile.organization&.address&.address
|
||||
end
|
||||
end
|
||||
end
|
||||
json.invoice_items invoice[:invoice].invoice_items do |item|
|
||||
|
@ -42,7 +42,7 @@ wb.add_worksheet(name: t('export_members.members')) do |sheet|
|
||||
member.profile.first_name,
|
||||
member.email,
|
||||
member.is_allow_newsletter,
|
||||
member.profile.gender ? t('export_members.man') : t('export_members.woman'),
|
||||
member.statistic_profile.gender ? t('export_members.man') : t('export_members.woman'),
|
||||
member.profile.age,
|
||||
member.invoicing_profile.address ? member.invoicing_profile.address.address : '',
|
||||
member.profile.phone,
|
||||
|
@ -86,6 +86,7 @@ en:
|
||||
i_ve_read_and_i_accept_: "I've read and I accept"
|
||||
_the_fablab_policy: "the FabLab policy"
|
||||
field_required: "Field required"
|
||||
unexpected_error_occurred: "An unexpected error occurred. Please try again later."
|
||||
|
||||
# password modification modal
|
||||
change_your_password: "Change your password"
|
||||
|
@ -84,7 +84,8 @@ es:
|
||||
i_accept_to_receive_information_from_the_fablab: "Acepto recibir información del FabLab"
|
||||
i_ve_read_and_i_accept_: "He leido y acepto"
|
||||
_the_fablab_policy: "la política de FabLab"
|
||||
field_required: "Field required" #translation_missing
|
||||
field_required: "Field required" # translation missing
|
||||
unexpected_error_occurred: "An unexpected error occurred. Please try again later." # translation missing
|
||||
|
||||
# password modification modal
|
||||
change_your_password: "Cambiar contraseña"
|
||||
|
@ -86,6 +86,7 @@ fr:
|
||||
i_ve_read_and_i_accept_: "J'ai lu et j'accepte"
|
||||
_the_fablab_policy: "la charte d'utilisation du Fab Lab"
|
||||
field_required: "Champ requis"
|
||||
unexpected_error_occurred: "Une erreur inattendue s'est produite. Veuillez réessayer ultérieurement."
|
||||
|
||||
# fenêtre de changement de mot de passe
|
||||
change_your_password: "Modifier votre mot de passe"
|
||||
|
@ -85,7 +85,8 @@ pt:
|
||||
i_accept_to_receive_information_from_the_fablab: "Eu aceito receber informações do FabLab"
|
||||
i_ve_read_and_i_accept_: "Eu li e aceito"
|
||||
_the_fablab_policy: "a política do FabLab"
|
||||
field_required: "Field required" #translation_missing
|
||||
field_required: "Field required" # translation missing
|
||||
unexpected_error_occurred: "An unexpected error occurred. Please try again later." # translation missing
|
||||
|
||||
# password modification modal
|
||||
change_your_password: "Mudar sua senha"
|
||||
|
@ -7,12 +7,14 @@ Rails.application.routes.draw do
|
||||
|
||||
if AuthProvider.active.providable_type == DatabaseProvider.name
|
||||
# with local authentification we do not use omniAuth so we must differentiate the config
|
||||
devise_for :users, controllers: {registrations: 'registrations', sessions: 'sessions',
|
||||
confirmations: 'confirmations', passwords: 'passwords'}
|
||||
devise_for :users, controllers: {
|
||||
registrations: 'registrations', sessions: 'sessions', confirmations: 'confirmations', passwords: 'passwords'
|
||||
}
|
||||
else
|
||||
devise_for :users, controllers: {registrations: 'registrations', sessions: 'sessions',
|
||||
confirmations: 'confirmations', passwords: 'passwords',
|
||||
:omniauth_callbacks => 'users/omniauth_callbacks'}
|
||||
devise_for :users, controllers: {
|
||||
registrations: 'registrations', sessions: 'sessions', confirmations: 'confirmations', passwords: 'passwords',
|
||||
omniauth_callbacks: 'users/omniauth_callbacks'
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
|
@ -11,5 +11,8 @@ class CreateInvoicingProfiles < ActiveRecord::Migration
|
||||
|
||||
add_reference :organizations, :invoicing_profile, index: true, foreign_key: true
|
||||
add_reference :invoices, :invoicing_profile, index: true, foreign_key: true
|
||||
add_reference :wallets, :invoicing_profile, index: true, foreign_key: true
|
||||
add_reference :wallet_transactions, :invoicing_profile, index: true, foreign_key: true
|
||||
add_reference :history_values, :invoicing_profile, index: true, foreign_key: true
|
||||
end
|
||||
end
|
||||
|
9
db/migrate/20190528140012_remove_user_id_columns.rb
Normal file
9
db/migrate/20190528140012_remove_user_id_columns.rb
Normal file
@ -0,0 +1,9 @@
|
||||
class RemoveUserIdColumns < ActiveRecord::Migration
|
||||
def change
|
||||
remove_column :invoices, :user_id, :integer
|
||||
remove_reference :organizations, :profile, index: true, foreign_key: true
|
||||
remove_reference :wallets, :user, index: true, foreign_key: true
|
||||
remove_reference :wallet_transactions, :user, index: true, foreign_key: true
|
||||
remove_reference :history_values, :user, index: true, foreign_key: true
|
||||
end
|
||||
end
|
@ -1,5 +0,0 @@
|
||||
class RemoveUserIdFromInvoice < ActiveRecord::Migration
|
||||
def change
|
||||
remove_column :invoices, :user_id, :integer
|
||||
end
|
||||
end
|
@ -1,5 +0,0 @@
|
||||
class RemoveProfileFromOrganization < ActiveRecord::Migration
|
||||
def change
|
||||
remove_reference :organizations, :profile, index: true, foreign_key: true
|
||||
end
|
||||
end
|
@ -1,6 +0,0 @@
|
||||
class AddInvoicingProfileToWallet < ActiveRecord::Migration
|
||||
def change
|
||||
add_reference :wallets, :invoicing_profile, index: true, foreign_key: true
|
||||
add_reference :wallet_transactions, :invoicing_profile, index: true, foreign_key: true
|
||||
end
|
||||
end
|
@ -1,6 +0,0 @@
|
||||
class RemoveUserIdFromWallet < ActiveRecord::Migration
|
||||
def change
|
||||
remove_reference :wallets, :user, index: true, foreign_key: true
|
||||
remove_reference :wallet_transactions, :user, index: true, foreign_key: true
|
||||
end
|
||||
end
|
@ -1,5 +0,0 @@
|
||||
class AddInvoicingProfileToHistoryValue < ActiveRecord::Migration
|
||||
def change
|
||||
add_reference :history_values, :invoicing_profile, index: true, foreign_key: true
|
||||
end
|
||||
end
|
@ -1,5 +0,0 @@
|
||||
class RemoveUserIdFromHistoryValue < ActiveRecord::Migration
|
||||
def change
|
||||
remove_reference :history_values, :user, index: true, foreign_key: true
|
||||
end
|
||||
end
|
13
db/migrate/20190603150642_create_statistic_profile.rb
Normal file
13
db/migrate/20190603150642_create_statistic_profile.rb
Normal file
@ -0,0 +1,13 @@
|
||||
class CreateStatisticProfile < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :statistic_profiles do |t|
|
||||
t.boolean :gender
|
||||
t.date :birthday
|
||||
t.belongs_to :group, index: true, foreign_key: true
|
||||
t.belongs_to :user, index: true, foreign_key: true
|
||||
end
|
||||
|
||||
add_reference :reservations, :statistic_profile, index: true, foreign_key: true
|
||||
add_reference :subscriptions, :statistic_profile, index: true, foreign_key: true
|
||||
end
|
||||
end
|
@ -0,0 +1,27 @@
|
||||
class MigrateProfileToStatisticProfile < ActiveRecord::Migration
|
||||
def up
|
||||
User.all.each do |u|
|
||||
p = u.profile
|
||||
puts "WARNING: User #{u.id} has no profile" and next unless p
|
||||
|
||||
StatisticProfile.create!(
|
||||
user: u,
|
||||
group: u.group,
|
||||
gender: p.gender,
|
||||
birthday: p.birthday
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
StatisticProfile.all.each do |sp|
|
||||
p = sp.user.profile
|
||||
puts "WARNING: User #{sp.user_id} has no profile" and next unless p
|
||||
|
||||
p.update_attributes(
|
||||
gender: sp.gender,
|
||||
birthday: sp.birthday
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,19 @@
|
||||
class MigrateReservationToStatisticProfile < ActiveRecord::Migration
|
||||
def up
|
||||
Reservation.all.each do |r|
|
||||
user = User.find(r.user_id)
|
||||
r.update_column(
|
||||
'statistic_profile_id', user.statistic_profile.id
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
Reservation.all.each do |r|
|
||||
statistic_profile = User.find(r.statistic_profile_id)
|
||||
r.update_column(
|
||||
'user_id', statistic_profile.user_id
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,19 @@
|
||||
class MigrateSubscriptionToStatisticProfile < ActiveRecord::Migration
|
||||
def up
|
||||
Subscription.all.each do |s|
|
||||
user = User.find(s.user_id)
|
||||
s.update_column(
|
||||
'statistic_profile_id', user.statistic_profile.id
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
Subscription.all.each do |s|
|
||||
statistic_profile = User.find(s.statistic_profile_id)
|
||||
s.update_column(
|
||||
'user_id', statistic_profile.user_id
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
8
db/migrate/20190604075717_remove_statistic_columns.rb
Normal file
8
db/migrate/20190604075717_remove_statistic_columns.rb
Normal file
@ -0,0 +1,8 @@
|
||||
class RemoveStatisticColumns < ActiveRecord::Migration
|
||||
def change
|
||||
remove_column :profiles, :gender, :boolean
|
||||
remove_column :profiles, :birthday, :date
|
||||
remove_column :reservations, :user_id
|
||||
remove_column :subscriptions, :user_id
|
||||
end
|
||||
end
|
32
db/schema.rb
32
db/schema.rb
@ -11,7 +11,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20190603141109) do
|
||||
ActiveRecord::Schema.define(version: 20190604075717) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
@ -447,8 +447,6 @@ ActiveRecord::Schema.define(version: 20190603141109) do
|
||||
t.integer "user_id"
|
||||
t.string "first_name", limit: 255
|
||||
t.string "last_name", limit: 255
|
||||
t.boolean "gender"
|
||||
t.date "birthday"
|
||||
t.string "phone", limit: 255
|
||||
t.text "interest"
|
||||
t.text "software_mastered"
|
||||
@ -545,19 +543,19 @@ ActiveRecord::Schema.define(version: 20190603141109) do
|
||||
add_index "projects_themes", ["theme_id"], name: "index_projects_themes_on_theme_id", using: :btree
|
||||
|
||||
create_table "reservations", force: :cascade do |t|
|
||||
t.integer "user_id"
|
||||
t.text "message"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.integer "reservable_id"
|
||||
t.string "reservable_type", limit: 255
|
||||
t.string "stp_invoice_id", limit: 255
|
||||
t.string "reservable_type", limit: 255
|
||||
t.string "stp_invoice_id", limit: 255
|
||||
t.integer "nb_reserve_places"
|
||||
t.integer "statistic_profile_id"
|
||||
end
|
||||
|
||||
add_index "reservations", ["reservable_id", "reservable_type"], name: "index_reservations_on_reservable_id_and_reservable_type", using: :btree
|
||||
add_index "reservations", ["statistic_profile_id"], name: "index_reservations_on_statistic_profile_id", using: :btree
|
||||
add_index "reservations", ["stp_invoice_id"], name: "index_reservations_on_stp_invoice_id", using: :btree
|
||||
add_index "reservations", ["user_id"], name: "index_reservations_on_user_id", using: :btree
|
||||
|
||||
create_table "roles", force: :cascade do |t|
|
||||
t.string "name", limit: 255
|
||||
@ -664,6 +662,16 @@ ActiveRecord::Schema.define(version: 20190603141109) do
|
||||
t.boolean "ca", default: true
|
||||
end
|
||||
|
||||
create_table "statistic_profiles", force: :cascade do |t|
|
||||
t.boolean "gender"
|
||||
t.date "birthday"
|
||||
t.integer "group_id"
|
||||
t.integer "user_id"
|
||||
end
|
||||
|
||||
add_index "statistic_profiles", ["group_id"], name: "index_statistic_profiles_on_group_id", using: :btree
|
||||
add_index "statistic_profiles", ["user_id"], name: "index_statistic_profiles_on_user_id", using: :btree
|
||||
|
||||
create_table "statistic_sub_types", force: :cascade do |t|
|
||||
t.string "key", limit: 255
|
||||
t.string "label", limit: 255
|
||||
@ -701,16 +709,16 @@ ActiveRecord::Schema.define(version: 20190603141109) do
|
||||
|
||||
create_table "subscriptions", force: :cascade do |t|
|
||||
t.integer "plan_id"
|
||||
t.integer "user_id"
|
||||
t.string "stp_subscription_id", limit: 255
|
||||
t.string "stp_subscription_id", limit: 255
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "expiration_date"
|
||||
t.datetime "canceled_at"
|
||||
t.integer "statistic_profile_id"
|
||||
end
|
||||
|
||||
add_index "subscriptions", ["plan_id"], name: "index_subscriptions_on_plan_id", using: :btree
|
||||
add_index "subscriptions", ["user_id"], name: "index_subscriptions_on_user_id", using: :btree
|
||||
add_index "subscriptions", ["statistic_profile_id"], name: "index_subscriptions_on_statistic_profile_id", using: :btree
|
||||
|
||||
create_table "tags", force: :cascade do |t|
|
||||
t.string "name"
|
||||
@ -906,11 +914,15 @@ ActiveRecord::Schema.define(version: 20190603141109) do
|
||||
add_foreign_key "prices", "plans"
|
||||
add_foreign_key "projects_spaces", "projects"
|
||||
add_foreign_key "projects_spaces", "spaces"
|
||||
add_foreign_key "reservations", "statistic_profiles"
|
||||
add_foreign_key "slots_reservations", "reservations"
|
||||
add_foreign_key "slots_reservations", "slots"
|
||||
add_foreign_key "spaces_availabilities", "availabilities"
|
||||
add_foreign_key "spaces_availabilities", "spaces"
|
||||
add_foreign_key "statistic_custom_aggregations", "statistic_types"
|
||||
add_foreign_key "statistic_profiles", "groups"
|
||||
add_foreign_key "statistic_profiles", "users"
|
||||
add_foreign_key "subscriptions", "statistic_profiles"
|
||||
add_foreign_key "tickets", "event_price_categories"
|
||||
add_foreign_key "tickets", "reservations"
|
||||
add_foreign_key "user_tags", "tags"
|
||||
|
@ -89,7 +89,8 @@ Group.create! name: I18n.t('group.admins'), slug: 'admins' unless Group.find_by(
|
||||
if Role.where(name: 'admin').joins(:users).count.zero?
|
||||
admin = User.new(username: 'admin', email: ENV['ADMIN_EMAIL'], password: ENV['ADMIN_PASSWORD'],
|
||||
password_confirmation: Rails.application.secrets.admin_password, group_id: Group.find_by(slug: 'admins').id,
|
||||
profile_attributes: { first_name: 'admin', last_name: 'admin', gender: true, phone: '0123456789', birthday: Time.now })
|
||||
profile_attributes: { first_name: 'admin', last_name: 'admin', phone: '0123456789' },
|
||||
statistic_profile_attributes: { gender: true, birthday: Time.now })
|
||||
admin.add_role 'admin'
|
||||
admin.save!
|
||||
end
|
||||
|
@ -42,12 +42,12 @@ This can be achieved doing the following:
|
||||
## Using another DBMS
|
||||
Some users may want to use another DBMS than PostgreSQL.
|
||||
This is currently not supported, because of some PostgreSQL specific instructions that cannot be efficiently handled with the ActiveRecord ORM:
|
||||
- `app/controllers/api/members_controllers.rb@list` is using `ILIKE`
|
||||
- `app/controllers/api/invoices_controllers.rb@list` is using `ILIKE` and `date_trunc()`
|
||||
- `app/services/members/list_service.rb@list` is using `ILIKE`, `now()::date` and `OFFSET`.
|
||||
- `app/services/invoices_service.rb@list` is using `ILIKE` and `date_trunc()`
|
||||
- `db/migrate/20160613093842_create_unaccent_function.rb` is using [unaccent](https://www.postgresql.org/docs/current/static/unaccent.html) and [trigram](https://www.postgresql.org/docs/current/static/pgtrgm.html) modules and defines a PL/pgSQL function (`f_unaccent()`)
|
||||
- `app/controllers/api/members_controllers.rb@search` is using `f_unaccent()` (see above) and `regexp_replace()`
|
||||
- `db/migrate/20150604131525_add_meta_data_to_notifications.rb` is using [jsonb](https://www.postgresql.org/docs/9.4/static/datatype-json.html), a PostgreSQL 9.4+ datatype.
|
||||
- `db/migrate/20160915105234_add_transformation_to_o_auth2_mapping.rb` is using [jsonb](https://www.postgresql.org/docs/9.4/static/datatype-json.html), a PostgreSQL 9.4+ datatype.
|
||||
- `db/migrate/20181217103441_migrate_settings_value_to_history_values.rb` is using `SELECT DISTINCT ON`.
|
||||
- `db/migrate/20190107111749_protect_accounting_periods.rb` is using `CREATE RULE` and `DROP RULE`.
|
||||
- `db/migrate/20190522115230_migrate_user_to_invoicing_profile.rb` is using `CREATE RULE` and `DROP RULE`.
|
||||
- `db/migrate/20190522115230_migrate_user_to_invoicing_profile.rb` is using `CREATE RULE` and `DROP RULE`.
|
||||
|
14
test/fixtures/profiles.yml
vendored
14
test/fixtures/profiles.yml
vendored
@ -4,8 +4,6 @@ profile_1:
|
||||
user_id: 1
|
||||
first_name: admin
|
||||
last_name: admin
|
||||
gender: true
|
||||
birthday: 2016-04-04
|
||||
phone: 0123456789
|
||||
interest:
|
||||
software_mastered:
|
||||
@ -17,8 +15,6 @@ profile_2:
|
||||
user_id: 2
|
||||
first_name: Jean
|
||||
last_name: Dupont
|
||||
gender: true
|
||||
birthday: 1975-06-07
|
||||
phone: '0214321420'
|
||||
interest: 3D printers
|
||||
software_mastered: autocad
|
||||
@ -30,8 +26,6 @@ profile_4:
|
||||
user_id: 4
|
||||
first_name: Kevin
|
||||
last_name: Dumas
|
||||
gender: true
|
||||
birthday: 1998-06-05
|
||||
phone: 0446124793
|
||||
interest: ''
|
||||
software_mastered: solidworks
|
||||
@ -43,8 +37,6 @@ profile_5:
|
||||
user_id: 5
|
||||
first_name: Vanessa
|
||||
last_name: Lonchamp
|
||||
gender: false
|
||||
birthday: 1994-05-03
|
||||
phone: 0233412482
|
||||
interest: vélo, natation
|
||||
software_mastered: ''
|
||||
@ -56,8 +48,6 @@ profile_6:
|
||||
user_id: 6
|
||||
first_name: Gilbert
|
||||
last_name: Partenaire
|
||||
gender: true
|
||||
birthday: 2016-04-04
|
||||
phone: '0000000000'
|
||||
interest:
|
||||
software_mastered:
|
||||
@ -69,8 +59,6 @@ profile_3:
|
||||
user_id: 3
|
||||
first_name: Paulette
|
||||
last_name: Durand
|
||||
gender: false
|
||||
birthday: 1949-06-18
|
||||
phone: '0474264261'
|
||||
interest: ''
|
||||
software_mastered: ''
|
||||
@ -82,8 +70,6 @@ profile_7:
|
||||
user_id: 7
|
||||
first_name: Lucile
|
||||
last_name: Seguin
|
||||
gender: false
|
||||
birthday: 1969-02-03
|
||||
phone: '0241853679'
|
||||
interest:
|
||||
software_mastered:
|
||||
|
4
test/fixtures/reservations.yml
vendored
4
test/fixtures/reservations.yml
vendored
@ -1,7 +1,7 @@
|
||||
|
||||
reservation_1:
|
||||
id: 1
|
||||
user_id: 7
|
||||
statistic_profile_id: 7
|
||||
message:
|
||||
created_at: 2012-03-12 11:03:31.651441000 Z
|
||||
updated_at: 2012-03-12 11:03:31.651441000 Z
|
||||
@ -12,7 +12,7 @@ reservation_1:
|
||||
|
||||
reservation_2:
|
||||
id: 2
|
||||
user_id: 3
|
||||
statistic_profile_id: 3
|
||||
message:
|
||||
created_at: 2015-06-10 11:20:01.341130000 Z
|
||||
updated_at: 2015-06-10 11:20:01.341130000 Z
|
||||
|
48
test/fixtures/statistic_profiles.yml
vendored
Normal file
48
test/fixtures/statistic_profiles.yml
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
admin:
|
||||
id: 1
|
||||
user_id: 1
|
||||
gender: true
|
||||
birthday: 2016-04-04
|
||||
group_id: 3
|
||||
|
||||
jdupont:
|
||||
id: 2
|
||||
user_id: 2
|
||||
gender: true
|
||||
birthday: 1975-06-07
|
||||
group_id: 1
|
||||
|
||||
kdumas:
|
||||
id: 4
|
||||
user_id: 4
|
||||
gender: true
|
||||
birthday: 1998-06-05
|
||||
group_id: 2
|
||||
|
||||
vlonchamp:
|
||||
id: 5
|
||||
user_id: 5
|
||||
gender: false
|
||||
birthday: 1994-05-03
|
||||
group_id: 2
|
||||
|
||||
gpartenaire:
|
||||
id: 6
|
||||
user_id: 6
|
||||
gender: true
|
||||
birthday: 2016-04-04
|
||||
group_id: 1
|
||||
|
||||
pdurand:
|
||||
id: 3
|
||||
user_id: 3
|
||||
gender: false
|
||||
birthday: 1949-06-18
|
||||
group_id: 1
|
||||
|
||||
lseguin:
|
||||
id: 7
|
||||
user_id: 7
|
||||
gender: false
|
||||
birthday: 1969-02-03
|
||||
group_id: 1
|
6
test/fixtures/subscriptions.yml
vendored
6
test/fixtures/subscriptions.yml
vendored
@ -2,7 +2,7 @@
|
||||
subscription_1:
|
||||
id: 1
|
||||
plan_id: 2
|
||||
user_id: 3
|
||||
statistic_profile_id: 3
|
||||
stp_subscription_id: sub_8DGB4ErIc2asOv
|
||||
created_at: <%= 10.days.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %>
|
||||
updated_at: <%= 10.days.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %>
|
||||
@ -12,7 +12,7 @@ subscription_1:
|
||||
subscription_2:
|
||||
id: 2
|
||||
plan_id: 3
|
||||
user_id: 4
|
||||
statistic_profile_id: 4
|
||||
stp_subscription_id:
|
||||
created_at: <%= 10.days.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %>
|
||||
updated_at: <%= 10.days.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %>
|
||||
@ -23,7 +23,7 @@ subscription_2:
|
||||
subscription_3:
|
||||
id: 3
|
||||
plan_id: 1
|
||||
user_id: 7
|
||||
statistic_profile_id: 7
|
||||
stp_subscription_id:
|
||||
created_at: 2012-03-12 11:03:31.651441000 Z
|
||||
updated_at: 2012-03-12 11:03:31.651441000 Z
|
||||
|
@ -23,14 +23,16 @@ class AdminsTest < ActionDispatch::IntegrationTest
|
||||
profile_attributes: {
|
||||
first_name: 'Gérard',
|
||||
last_name: 'Lepower',
|
||||
gender: true,
|
||||
birthday: '1999-09-19',
|
||||
phone: '0547124852',
|
||||
phone: '0547124852'
|
||||
},
|
||||
invoicing_profile_attributes: {
|
||||
address_attributes: {
|
||||
address: '6 Avenue Henri de Bournazel, 19000 Tulle'
|
||||
}
|
||||
},
|
||||
statistic_profile_attributes: {
|
||||
gender: true,
|
||||
birthday: '1999-09-19'
|
||||
}
|
||||
}
|
||||
}.to_json,
|
||||
|
@ -20,16 +20,18 @@ class MembersTest < ActionDispatch::IntegrationTest
|
||||
email: email,
|
||||
group_id: group_id,
|
||||
profile_attributes: {
|
||||
gender: true,
|
||||
last_name: 'Dubois',
|
||||
first_name: 'Robert',
|
||||
birthday: '2018-02-08',
|
||||
phone: '0485232145'
|
||||
},
|
||||
invoicing_profile_attributes: {
|
||||
address_attributes: {
|
||||
address: '21 grand rue, 73110 Bourget-en-Huile'
|
||||
}
|
||||
},
|
||||
statistic_profile_attributes: {
|
||||
gender: true,
|
||||
birthday: '2018-02-08'
|
||||
}
|
||||
} }.to_json, default_headers
|
||||
end
|
||||
|
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Subscriptions
|
||||
class CreateAsAdminTest < ActionDispatch::IntegrationTest
|
||||
|
||||
@ -7,11 +9,11 @@ module Subscriptions
|
||||
login_as(@admin, scope: :user)
|
||||
end
|
||||
|
||||
test "admin successfully takes a subscription for a user" do
|
||||
test 'admin successfully takes a subscription for a user' do
|
||||
user = User.find_by(username: 'jdupond')
|
||||
plan = Plan.find_by(group_id: user.group.id, type: 'Plan', base_name: 'Mensuel')
|
||||
|
||||
VCR.use_cassette("subscriptions_admin_create_success") do
|
||||
VCR.use_cassette('subscriptions_admin_create_success') do
|
||||
post '/api/subscriptions',
|
||||
{
|
||||
subscription: {
|
||||
|
@ -1,9 +1,15 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'test_helper'
|
||||
|
||||
class UserTest < ActiveSupport::TestCase
|
||||
test "must create a wallet after create user" do
|
||||
test 'must create wallet and profiles after create user' do
|
||||
u = User.create(username: 'user', email: 'userwallet@fabmanager.com', password: 'testpassword', password_confirmation: 'testpassword',
|
||||
profile_attributes: {first_name: 'user', last_name: 'wallet', gender: true, birthday: 18.years.ago, phone: '0123456789'} )
|
||||
profile_attributes: { first_name: 'user', last_name: 'wallet', phone: '0123456789' },
|
||||
statistic_profile_attributes: { gender: true, birthday: 18.years.ago })
|
||||
assert u.wallet.present?
|
||||
assert u.profile.present?
|
||||
assert u.invoicing_profile.present?
|
||||
assert u.statistic_profile.present?
|
||||
end
|
||||
end
|
||||
|
@ -8,14 +8,14 @@ class SubscriptionExtensionAfterReservationTest < ActiveSupport::TestCase
|
||||
@plan = Plan.find(3)
|
||||
@plan.update!(is_rolling: true)
|
||||
|
||||
@user = User.joins(:subscriptions).find_by(subscriptions: { plan: @plan })
|
||||
@user = User.joins(statistic_profile: [:subscriptions]).find_by(subscriptions: { plan_id: @plan.id })
|
||||
|
||||
@user.reservations.destroy_all # ensure no reservations
|
||||
|
||||
@availability = @machine.availabilities.first
|
||||
slot = Slot.new(start_at: @availability.start_at, end_at: @availability.end_at, availability_id: @availability.id)
|
||||
@reservation_machine = Reservation.new(user: @user, reservable: @machine, slots: [slot])
|
||||
@reservation_training = Reservation.new(user: @user, reservable: @training, slots: [slot])
|
||||
@reservation_machine = Reservation.new(statistic_profile: @user.statistic_profile, reservable: @machine, slots: [slot])
|
||||
@reservation_training = Reservation.new(statistic_profile: @user.statistic_profile, reservable: @training, slots: [slot])
|
||||
@reservation_training.save!
|
||||
end
|
||||
|
||||
|
@ -5,11 +5,11 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase
|
||||
@machine = Machine.find(6)
|
||||
@training = Training.find(2)
|
||||
@plan = Plan.find(3)
|
||||
@user = User.joins(:subscriptions).find_by(subscriptions: { plan: @plan })
|
||||
@user = User.joins(statistic_profile: [:subscriptions]).find_by(subscriptions: { plan_id: @plan.id })
|
||||
@user.users_credits.destroy_all
|
||||
@availability = @machine.availabilities.first
|
||||
@reservation_machine = Reservation.new(user: @user, reservable: @machine)
|
||||
@reservation_training = Reservation.new(user: @user, reservable: @training)
|
||||
@reservation_machine = Reservation.new(statistic_profile: @user.statistic_profile, reservable: @machine)
|
||||
@reservation_training = Reservation.new(statistic_profile: @user.statistic_profile, reservable: @training)
|
||||
end
|
||||
|
||||
## context machine reservation
|
||||
|
Loading…
x
Reference in New Issue
Block a user