mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-19 13:54:25 +01:00
Merge branch 'dev' into host
This commit is contained in:
commit
da672ea8b6
@ -1,5 +1,5 @@
|
||||
Metrics/LineLength:
|
||||
Max: 125
|
||||
Max: 130
|
||||
Metrics/MethodLength:
|
||||
Max: 30
|
||||
Metrics/CyclomaticComplexity:
|
||||
@ -8,6 +8,8 @@ Metrics/PerceivedComplexity:
|
||||
Max: 9
|
||||
Metrics/AbcSize:
|
||||
Max: 45
|
||||
Metrics/ClassLength:
|
||||
Max: 200
|
||||
Style/BracesAroundHashParameters:
|
||||
EnforcedStyle: context_dependent
|
||||
Style/RegexpLiteral:
|
||||
|
@ -1,10 +1,16 @@
|
||||
# Changelog Fab Manager
|
||||
|
||||
- Removed ability to disable invoicing for an user
|
||||
- Fixed a missing translation in plan form
|
||||
- Fix a bug: error handling on password recovery
|
||||
- Fix a bug: error handling on machine attachment upload
|
||||
- Fix a bug: first day of week is ignored in statistics custom filter
|
||||
- Fix a bug: rails DSB locale is invalid
|
||||
- Removed ability to disable invoicing for an user
|
||||
- Fix a bug: unable to delete an admin who has changed a setting
|
||||
- Fix a bug: unable to create/edit a plan of 12 months or 52 weeks
|
||||
- Fix a bug: Unable to search in user autocomplete fields
|
||||
- Fix a bug: Invalid translation in new partner modal
|
||||
- Improved user autocompletion when using multiple words
|
||||
- Refactored frontend invoices translations
|
||||
- Updated RailRoady 1.4.0 to 1.5.3
|
||||
|
||||
|
@ -160,10 +160,14 @@ This procedure is not easy to follow so if you don't need to write some code for
|
||||
- **Please note**: Your password length must be between 8 and 128 characters, otherwise db:seed will be rejected. This is configured in [config/initializers/devise.rb](config/initializers/devise.rb)
|
||||
|
||||
```bash
|
||||
# for dev
|
||||
rake db:create
|
||||
rake db:migrate
|
||||
ADMIN_EMAIL='youradminemail' ADMIN_PASSWORD='youradminpassword' rake db:seed
|
||||
rake fablab:es_build_stats
|
||||
# for tests
|
||||
RAILS_ENV=test rake db:create
|
||||
RAILS_ENV=test rake db:migrate
|
||||
```
|
||||
|
||||
14. Create the pids folder used by Sidekiq. If you want to use a different location, you can configure it in `config/sidekiq.yml`
|
||||
@ -252,6 +256,9 @@ environment.
|
||||
rake db:migrate
|
||||
ADMIN_EMAIL='youradminemail' ADMIN_PASSWORD='youradminpassword' rake db:seed
|
||||
rake fablab:es_build_stats
|
||||
# for tests
|
||||
RAILS_ENV=test rake db:create
|
||||
RAILS_ENV=test rake db:migrate
|
||||
```
|
||||
|
||||
11. Start the application and visit `localhost:3000` on your browser to check that it works:
|
||||
|
@ -180,6 +180,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.no-user-label {
|
||||
font-style: italic;
|
||||
color: #5a5a5a;
|
||||
}
|
||||
|
||||
|
||||
table.closings-table {
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
|
@ -403,7 +403,7 @@
|
||||
<tr ng-repeat="value in history">
|
||||
<td>{{value.value}} %</td>
|
||||
<td>{{value.created_at | amDateFormat:'L LT'}}</td>
|
||||
<td>{{value.user.name}}</td>
|
||||
<td>{{value.user.name}}<span class="no-user-label" ng-hide="value.user" translate>{{ 'invoices.deleted_user' }}</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title" translate>{{ 'new_partner' }}</h3>
|
||||
<h3 class="modal-title" translate>{{ 'plan_form.new_partner' }}</h3>
|
||||
</div>
|
||||
<div class="modal-body m-lg">
|
||||
<form name="partnerForm">
|
||||
|
@ -34,7 +34,7 @@ class API::AdminsController < API::ApiController
|
||||
|
||||
def destroy
|
||||
@admin = User.admins.find(params[:id])
|
||||
if current_user.admin? and @admin != current_user
|
||||
if current_user.admin? && @admin != current_user
|
||||
@admin.destroy
|
||||
head :no_content
|
||||
else
|
||||
|
@ -22,7 +22,6 @@ class API::AgeRangesController < API::ApiController
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def update
|
||||
authorize AgeRange
|
||||
if @age_range.update(age_range_params)
|
||||
@ -42,6 +41,7 @@ class API::AgeRangesController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_age_range
|
||||
@age_range = AgeRange.find(params[:id])
|
||||
end
|
||||
|
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class API::ApiController < ApplicationController
|
||||
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type AuthProvider
|
||||
# AuthProvider are used to connect users through single-sign on systems
|
||||
class API::AuthProvidersController < API::ApiController
|
||||
|
||||
before_action :set_provider, only: [:show, :update, :destroy]
|
||||
before_action :set_provider, only: %i[show update destroy]
|
||||
def index
|
||||
@providers = policy_scope(AuthProvider)
|
||||
end
|
||||
@ -57,33 +61,33 @@ class API::AuthProvidersController < API::ApiController
|
||||
NotificationCenter.call type: 'notify_user_auth_migration',
|
||||
receiver: user,
|
||||
attached_object: user
|
||||
render json: {status: 'processing'}, status: :ok
|
||||
render json: { status: 'processing' }, status: :ok
|
||||
else
|
||||
render json: {status: 'error', error: I18n.t('members.current_authentication_method_no_code')}, status: :bad_request
|
||||
render json: { status: 'error', error: I18n.t('members.current_authentication_method_no_code') }, status: :bad_request
|
||||
end
|
||||
else
|
||||
render json: {status: 'error', error: I18n.t('members.requested_account_does_not_exists')}, status: :bad_request
|
||||
render json: { status: 'error', error: I18n.t('members.requested_account_does_not_exists') }, status: :bad_request
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_provider
|
||||
@provider = AuthProvider.find(params[:id])
|
||||
end
|
||||
def set_provider
|
||||
@provider = AuthProvider.find(params[:id])
|
||||
end
|
||||
|
||||
def provider_params
|
||||
if params['auth_provider']['providable_type'] == DatabaseProvider.name
|
||||
params.require(:auth_provider).permit(:name, :providable_type)
|
||||
elsif params['auth_provider']['providable_type'] == OAuth2Provider.name
|
||||
params.require(:auth_provider).permit(:name, :providable_type, providable_attributes: [
|
||||
:id, :base_url, :token_endpoint, :authorization_endpoint, :logout_endpoint, :profile_url, :client_id, :client_secret,
|
||||
o_auth2_mappings_attributes: [
|
||||
:id, :local_model, :local_field, :api_field, :api_endpoint, :api_data_type, :_destroy,
|
||||
transformation: [:type, :format, :true_value, :false_value, mapping: [:from, :to]]
|
||||
]
|
||||
])
|
||||
end
|
||||
def provider_params
|
||||
if params['auth_provider']['providable_type'] == DatabaseProvider.name
|
||||
params.require(:auth_provider).permit(:name, :providable_type)
|
||||
elsif params['auth_provider']['providable_type'] == OAuth2Provider.name
|
||||
params.require(:auth_provider)
|
||||
.permit(:name, :providable_type,
|
||||
providable_attributes: [:id, :base_url, :token_endpoint, :authorization_endpoint, :logout_endpoint,
|
||||
:profile_url, :client_id, :client_secret,
|
||||
o_auth2_mappings_attributes: [:id, :local_model, :local_field, :api_field,
|
||||
:api_endpoint, :api_data_type, :_destroy,
|
||||
transformation: [:type, :format, :true_value,
|
||||
:false_value, mapping: %i[from to]]]])
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Availability
|
||||
class API::AvailabilitiesController < API::ApiController
|
||||
include FablabConfiguration
|
||||
|
||||
@ -10,94 +13,30 @@ class API::AvailabilitiesController < API::ApiController
|
||||
authorize Availability
|
||||
start_date = ActiveSupport::TimeZone[params[:timezone]].parse(params[:start])
|
||||
end_date = ActiveSupport::TimeZone[params[:timezone]].parse(params[:end]).end_of_day
|
||||
@availabilities = Availability.includes(:machines, :tags, :trainings, :spaces).where.not(available_type: 'event')
|
||||
@availabilities = Availability.includes(:machines, :tags, :trainings, :spaces)
|
||||
.where.not(available_type: 'event')
|
||||
.where('start_at >= ? AND end_at <= ?', start_date, end_date)
|
||||
|
||||
if fablab_spaces_deactivated?
|
||||
@availabilities = @availabilities.where.not(available_type: 'space')
|
||||
end
|
||||
@availabilities = @availabilities.where.not(available_type: 'space') if fablab_spaces_deactivated?
|
||||
end
|
||||
|
||||
def public
|
||||
start_date = ActiveSupport::TimeZone[params[:timezone]].parse(params[:start])
|
||||
end_date = ActiveSupport::TimeZone[params[:timezone]].parse(params[:end]).end_of_day
|
||||
@reservations = Reservation.includes(:slots, user: [:profile]).references(:slots, :user)
|
||||
.where('slots.start_at >= ? AND slots.end_at <= ?', start_date, end_date)
|
||||
@reservations = Reservation.includes(:slots, user: [:profile])
|
||||
.references(:slots, :user)
|
||||
.where('slots.start_at >= ? AND slots.end_at <= ?', start_date, end_date)
|
||||
|
||||
# request for 1 single day
|
||||
if in_same_day(start_date, end_date)
|
||||
# trainings, events
|
||||
@training_and_event_availabilities = Availability.includes(:tags, :trainings, :event, :slots)
|
||||
.where(available_type: %w[training event])
|
||||
.where('start_at >= ? AND end_at <= ?', start_date, end_date)
|
||||
.where(lock: false)
|
||||
# machines
|
||||
@machine_availabilities = Availability.includes(:tags, :machines)
|
||||
.where(available_type: 'machines')
|
||||
.where('start_at >= ? AND end_at <= ?', start_date, end_date)
|
||||
.where(lock: false)
|
||||
@machine_slots = []
|
||||
@machine_availabilities.each do |a|
|
||||
a.machines.each do |machine|
|
||||
next unless params[:m]&.include?(machine.id.to_s)
|
||||
|
||||
((a.end_at - a.start_at)/ApplicationHelper::SLOT_DURATION.minutes).to_i.times do |i|
|
||||
slot = Slot.new(
|
||||
start_at: a.start_at + (i*ApplicationHelper::SLOT_DURATION).minutes,
|
||||
end_at: a.start_at + (i*ApplicationHelper::SLOT_DURATION).minutes + ApplicationHelper::SLOT_DURATION.minutes,
|
||||
availability_id: a.id,
|
||||
availability: a,
|
||||
machine: machine,
|
||||
title: machine.name
|
||||
)
|
||||
slot = verify_machine_is_reserved(slot, @reservations, current_user, '')
|
||||
@machine_slots << slot
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# spaces
|
||||
@space_availabilities = Availability.includes(:tags, :spaces).where(available_type: 'space')
|
||||
.where('start_at >= ? AND end_at <= ?', start_date, end_date)
|
||||
.where(lock: false)
|
||||
|
||||
@space_availabilities.where(available_id: params[:s]) if params[:s]
|
||||
|
||||
@space_slots = []
|
||||
@space_availabilities.each do |a|
|
||||
space = a.spaces.first
|
||||
((a.end_at - a.start_at)/ApplicationHelper::SLOT_DURATION.minutes).to_i.times do |i|
|
||||
next unless (a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes) > Time.now
|
||||
|
||||
slot = Slot.new(
|
||||
start_at: a.start_at + (i*ApplicationHelper::SLOT_DURATION).minutes,
|
||||
end_at: a.start_at + (i*ApplicationHelper::SLOT_DURATION).minutes + ApplicationHelper::SLOT_DURATION.minutes,
|
||||
availability_id: a.id,
|
||||
availability: a,
|
||||
space: space,
|
||||
title: space.name
|
||||
)
|
||||
slot = verify_space_is_reserved(slot, @reservations, current_user, '')
|
||||
@space_slots << slot
|
||||
end
|
||||
end
|
||||
@availabilities = [].concat(@training_and_event_availabilities).concat(@machine_slots).concat(@space_slots)
|
||||
|
||||
# request for many days (week or month)
|
||||
else
|
||||
@availabilities = Availability.includes(:tags, :machines, :trainings, :spaces, :event, :slots)
|
||||
.where('start_at >= ? AND end_at <= ?', start_date, end_date)
|
||||
.where(lock: false)
|
||||
@availabilities.each do |a|
|
||||
if a.available_type == 'training' or a.available_type == 'event'
|
||||
a = verify_training_event_is_reserved(a, @reservations, current_user)
|
||||
elsif a.available_type == 'space'
|
||||
a.is_reserved = is_reserved_availability(a, current_user)
|
||||
end
|
||||
end
|
||||
end
|
||||
machine_ids = params[:m] || []
|
||||
@title_filter = {machine_ids: machine_ids.map(&:to_i)}
|
||||
service = Availabilities::PublicAvailabilitiesService.new(current_user)
|
||||
@availabilities = service.public_availabilities(
|
||||
start_date,
|
||||
end_date,
|
||||
@reservations,
|
||||
machines: machine_ids, spaces: params[:s]
|
||||
)
|
||||
|
||||
@title_filter = { machine_ids: machine_ids.map(&:to_i) }
|
||||
@availabilities = filter_availabilites(@availabilities)
|
||||
end
|
||||
|
||||
@ -134,138 +73,22 @@ class API::AvailabilitiesController < API::ApiController
|
||||
end
|
||||
|
||||
def machine
|
||||
@user = if params[:member_id]
|
||||
User.find(params[:member_id])
|
||||
else
|
||||
current_user
|
||||
end
|
||||
@current_user_role = current_user.admin? ? 'admin' : 'user'
|
||||
@machine = Machine.friendly.find(params[:machine_id])
|
||||
@slots = []
|
||||
@reservations = Reservation.where('reservable_type = ? and reservable_id = ?', @machine.class.to_s, @machine.id)
|
||||
.includes(:slots, user: [:profile])
|
||||
.references(:slots, :user)
|
||||
.where('slots.start_at > ?', Time.now)
|
||||
if @user.admin?
|
||||
@availabilities = @machine.availabilities.includes(:tags)
|
||||
.where("end_at > ? AND available_type = 'machines'", Time.now)
|
||||
.where(lock: false)
|
||||
else
|
||||
end_at = @visi_max_other
|
||||
end_at = @visi_max_year if is_subscription_year(@user)
|
||||
@availabilities = @machine.availabilities
|
||||
.includes(:tags)
|
||||
.where("end_at > ? AND end_at < ? AND available_type = 'machines'", Time.now, end_at)
|
||||
.where('availability_tags.tag_id' => @user.tag_ids.concat([nil]))
|
||||
.where(lock: false)
|
||||
end
|
||||
@availabilities.each do |a|
|
||||
((a.end_at - a.start_at)/ApplicationHelper::SLOT_DURATION.minutes).to_i.times do |i|
|
||||
next unless (a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes) > Time.now
|
||||
|
||||
slot = Slot.new(
|
||||
start_at: a.start_at + (i*ApplicationHelper::SLOT_DURATION).minutes,
|
||||
end_at: a.start_at + (i*ApplicationHelper::SLOT_DURATION).minutes + ApplicationHelper::SLOT_DURATION.minutes,
|
||||
availability_id: a.id,
|
||||
availability: a,
|
||||
machine: @machine,
|
||||
title: ''
|
||||
)
|
||||
slot = verify_machine_is_reserved(slot, @reservations, current_user, @current_user_role)
|
||||
@slots << slot
|
||||
end
|
||||
end
|
||||
service = Availabilities::AvailabilitiesService.new(current_user, other: @visi_max_other, year: @visi_max_year)
|
||||
@slots = service.machines(params[:machine_id], user)
|
||||
end
|
||||
|
||||
def trainings
|
||||
@user = if params[:member_id]
|
||||
User.find(params[:member_id])
|
||||
else
|
||||
current_user
|
||||
end
|
||||
@slots = []
|
||||
|
||||
# first, we get the already-made reservations
|
||||
@reservations = @user.reservations.where("reservable_type = 'Training'")
|
||||
@reservations = @reservations.where('reservable_id = :id', id: params[:training_id].to_i) if params[:training_id].is_number?
|
||||
@reservations = @reservations.joins(:slots).where('slots.start_at > ?', Time.now)
|
||||
|
||||
# what is requested?
|
||||
# 1) a single training
|
||||
@availabilities = if params[:training_id].is_number? or (params[:training_id].length > 0 and params[:training_id] != 'all')
|
||||
Training.friendly.find(params[:training_id]).availabilities
|
||||
# 2) all trainings
|
||||
else
|
||||
Availability.trainings
|
||||
end
|
||||
|
||||
# who made the request?
|
||||
# 1) an admin (he can see all future availabilities)
|
||||
if current_user.admin?
|
||||
@availabilities = @availabilities.includes(:tags, :slots, trainings: [:machines])
|
||||
.where('availabilities.start_at > ?', Time.now)
|
||||
.where(lock: false)
|
||||
# 2) an user (he cannot see availabilities further than 1 (or 3) months)
|
||||
else
|
||||
end_at = @visi_max_year
|
||||
end_at = @visi_max_year if can_show_slot_plus_three_months(@user)
|
||||
@availabilities = @availabilities.includes(:tags, :slots, :availability_tags, trainings: [:machines])
|
||||
.where('availabilities.start_at > ? AND availabilities.start_at < ?', Time.now, end_at)
|
||||
.where('availability_tags.tag_id' => @user.tag_ids.concat([nil]))
|
||||
.where(lock: false)
|
||||
end
|
||||
|
||||
# finally, we merge the availabilities with the reservations
|
||||
@availabilities.each do |a|
|
||||
a = verify_training_event_is_reserved(a, @reservations, @user)
|
||||
end
|
||||
service = Availabilities::AvailabilitiesService.new(current_user, other: @visi_max_other, year: @visi_max_year)
|
||||
@availabilities = service.trainings(params[:training_id], user)
|
||||
end
|
||||
|
||||
def spaces
|
||||
@user = if params[:member_id]
|
||||
User.find(params[:member_id])
|
||||
else
|
||||
current_user
|
||||
end
|
||||
@current_user_role = current_user.admin? ? 'admin' : 'user'
|
||||
@space = Space.friendly.find(params[:space_id])
|
||||
@slots = []
|
||||
@reservations = Reservation.where('reservable_type = ? and reservable_id = ?', @space.class.to_s, @space.id)
|
||||
.includes(:slots, user: [:profile]).references(:slots, :user)
|
||||
.where('slots.start_at > ?', Time.now)
|
||||
if current_user.admin?
|
||||
@availabilities = @space.availabilities.includes(:tags)
|
||||
.where("end_at > ? AND available_type = 'space'", Time.now)
|
||||
.where(lock: false)
|
||||
else
|
||||
end_at = @visi_max_other
|
||||
end_at = @visi_max_year if is_subscription_year(@user)
|
||||
@availabilities = @space.availabilities.includes(:tags)
|
||||
.where("end_at > ? AND end_at < ? AND available_type = 'space'", Time.now, end_at)
|
||||
.where('availability_tags.tag_id' => @user.tag_ids.concat([nil]))
|
||||
.where(lock: false)
|
||||
end
|
||||
@availabilities.each do |a|
|
||||
((a.end_at - a.start_at)/ApplicationHelper::SLOT_DURATION.minutes).to_i.times do |i|
|
||||
next unless (a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes) > Time.now
|
||||
|
||||
slot = Slot.new(
|
||||
start_at: a.start_at + (i*ApplicationHelper::SLOT_DURATION).minutes,
|
||||
end_at: a.start_at + (i*ApplicationHelper::SLOT_DURATION).minutes + ApplicationHelper::SLOT_DURATION.minutes,
|
||||
availability_id: a.id,
|
||||
availability: a,
|
||||
space: @space,
|
||||
title: ''
|
||||
)
|
||||
slot = verify_space_is_reserved(slot, @reservations, @user, @current_user_role)
|
||||
@slots << slot
|
||||
end
|
||||
end
|
||||
@slots.each do |s|
|
||||
if s.is_complete? and not s.is_reserved
|
||||
s.title = t('availabilities.not_available')
|
||||
end
|
||||
end
|
||||
service = Availabilities::AvailabilitiesService.new(current_user, other: @visi_max_other, year: @visi_max_year)
|
||||
@slots = service.spaces(params[:space_id], user)
|
||||
end
|
||||
|
||||
def reservations
|
||||
@ -281,7 +104,7 @@ class API::AvailabilitiesController < API::ApiController
|
||||
if export.nil? || !FileTest.exist?(export.file)
|
||||
@export = Export.new(category: 'availabilities', export_type: 'index', user: current_user)
|
||||
if @export.save
|
||||
render json: {export_id: @export.id}, status: :ok
|
||||
render json: { export_id: @export.id }, status: :ok
|
||||
else
|
||||
render json: @export.errors, status: :unprocessable_entity
|
||||
end
|
||||
@ -303,6 +126,14 @@ class API::AvailabilitiesController < API::ApiController
|
||||
|
||||
private
|
||||
|
||||
def user
|
||||
if params[:member_id]
|
||||
User.find(params[:member_id])
|
||||
else
|
||||
current_user
|
||||
end
|
||||
end
|
||||
|
||||
def set_availability
|
||||
@availability = Availability.find(params[:id])
|
||||
end
|
||||
@ -317,104 +148,6 @@ class API::AvailabilitiesController < API::ApiController
|
||||
params.require(:lock)
|
||||
end
|
||||
|
||||
def is_reserved_availability(availability, user)
|
||||
if user
|
||||
reserved_slots = []
|
||||
availability.slots.each do |s|
|
||||
if s.canceled_at.nil?
|
||||
reserved_slots << s
|
||||
end
|
||||
end
|
||||
reserved_slots.map(&:reservations).flatten.map(&:user_id).include? user.id
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def is_reserved(start_at, reservations)
|
||||
is_reserved = false
|
||||
reservations.each do |r|
|
||||
r.slots.each do |s|
|
||||
is_reserved = true if s.start_at == start_at
|
||||
end
|
||||
end
|
||||
is_reserved
|
||||
end
|
||||
|
||||
def verify_machine_is_reserved(slot, reservations, user, user_role)
|
||||
show_name = (user_role == 'admin' or Setting.find_by(name: 'display_name_enable').value == 'true')
|
||||
reservations.each do |r|
|
||||
r.slots.each do |s|
|
||||
next unless slot.machine.id == r.reservable_id
|
||||
|
||||
if s.start_at == slot.start_at and s.canceled_at == nil
|
||||
slot.id = s.id
|
||||
slot.is_reserved = true
|
||||
slot.title = "#{slot.machine.name} - #{show_name ? r.user.profile.full_name : t('availabilities.not_available')}"
|
||||
slot.can_modify = true if user_role === 'admin'
|
||||
slot.reservations.push r
|
||||
end
|
||||
if s.start_at == slot.start_at and r.user == user and s.canceled_at == nil
|
||||
slot.title = "#{slot.machine.name} - #{t('availabilities.i_ve_reserved')}"
|
||||
slot.can_modify = true
|
||||
slot.is_reserved_by_current_user = true
|
||||
end
|
||||
end
|
||||
end
|
||||
slot
|
||||
end
|
||||
|
||||
def verify_space_is_reserved(slot, reservations, user, user_role)
|
||||
reservations.each do |r|
|
||||
r.slots.each do |s|
|
||||
next unless slot.space.id == r.reservable_id
|
||||
|
||||
if s.start_at == slot.start_at and s.canceled_at == nil
|
||||
slot.can_modify = true if user_role === 'admin'
|
||||
slot.reservations.push r
|
||||
end
|
||||
if s.start_at == slot.start_at and r.user == user and s.canceled_at == nil
|
||||
slot.id = s.id
|
||||
slot.title = t('availabilities.i_ve_reserved')
|
||||
slot.can_modify = true
|
||||
slot.is_reserved = true
|
||||
end
|
||||
end
|
||||
end
|
||||
slot
|
||||
end
|
||||
|
||||
def verify_training_event_is_reserved(availability, reservations, user)
|
||||
reservations.each do |r|
|
||||
r.slots.each do |s|
|
||||
next unless (
|
||||
(availability.available_type == 'training' && availability.trainings.first.id == r.reservable_id) ||
|
||||
(availability.available_type == 'event' && availability.event.id == r.reservable_id)
|
||||
) && s.start_at == availability.start_at && s.canceled_at == nil
|
||||
|
||||
availability.slot_id = s.id
|
||||
if r.user == user
|
||||
availability.is_reserved = true
|
||||
availability.can_modify = true
|
||||
end
|
||||
end
|
||||
end
|
||||
availability
|
||||
end
|
||||
|
||||
def can_show_slot_plus_three_months(user)
|
||||
# member must have validated at least 1 training and must have a valid yearly subscription.
|
||||
user.trainings.size > 0 and is_subscription_year(user)
|
||||
end
|
||||
|
||||
def is_subscription_year(user)
|
||||
user.subscription and user.subscription.plan.interval == 'year' and user.subscription.expired_at >= Time.now
|
||||
end
|
||||
|
||||
def in_same_day(start_date, end_date)
|
||||
(end_date.to_date - start_date.to_date).to_i == 1
|
||||
end
|
||||
|
||||
def filter_availabilites(availabilities)
|
||||
availabilities_filtered = []
|
||||
availabilities.to_ary.each do |a|
|
||||
@ -422,35 +155,33 @@ class API::AvailabilitiesController < API::ApiController
|
||||
if !a.try(:available_type)
|
||||
availabilities_filtered << a
|
||||
else
|
||||
# training
|
||||
if params[:t] and a.available_type == 'training'
|
||||
if params[:t].include?(a.trainings.first.id.to_s)
|
||||
availabilities_filtered << a
|
||||
end
|
||||
end
|
||||
# space
|
||||
if params[:s] and a.available_type == 'space'
|
||||
if params[:s].include?(a.spaces.first.id.to_s)
|
||||
availabilities_filtered << a
|
||||
end
|
||||
end
|
||||
# machines
|
||||
if params[:m] and a.available_type == 'machines'
|
||||
if (params[:m].map(&:to_i) & a.machine_ids).any?
|
||||
availabilities_filtered << a
|
||||
end
|
||||
end
|
||||
# event
|
||||
if params[:evt] and params[:evt] == 'true' and a.available_type == 'event'
|
||||
availabilities_filtered << a
|
||||
end
|
||||
end
|
||||
end
|
||||
availabilities_filtered.delete_if do |a|
|
||||
if params[:dispo] == 'false'
|
||||
a.is_reserved or (a.try(:completed?) and a.completed?)
|
||||
availabilities_filtered << a if filter_training?(a)
|
||||
availabilities_filtered << a if filter_space?(a)
|
||||
availabilities_filtered << a if filter_machine?(a)
|
||||
availabilities_filtered << a if filter_event?(a)
|
||||
end
|
||||
end
|
||||
availabilities_filtered.delete_if(&method(:remove_completed?))
|
||||
end
|
||||
|
||||
def filter_training?(availability)
|
||||
params[:t] && availability.available_type == 'training' && params[:t].include?(availability.trainings.first.id.to_s)
|
||||
end
|
||||
|
||||
def filter_space?(availability)
|
||||
params[:s] && availability.available_type == 'space' && params[:s].include?(availability.spaces.first.id.to_s)
|
||||
end
|
||||
|
||||
def filter_machine?(availability)
|
||||
params[:m] && availability.available_type == 'machines' && (params[:m].map(&:to_i) & availability.machine_ids).any?
|
||||
end
|
||||
|
||||
def filter_event?(availability)
|
||||
params[:evt] && params[:evt] == 'true' && availability.available_type == 'event'
|
||||
end
|
||||
|
||||
def remove_completed?(availability)
|
||||
params[:dispo] == 'false' && (availability.is_reserved || (availability.try(:completed?) && availability.completed?))
|
||||
end
|
||||
|
||||
def define_max_visibility
|
||||
|
@ -1,13 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Category
|
||||
# Categories are used to classify Events
|
||||
class API::CategoriesController < API::ApiController
|
||||
before_action :authenticate_user!, except: [:index]
|
||||
before_action :set_category, only: [:show, :update, :destroy]
|
||||
before_action :set_category, only: %i[show update destroy]
|
||||
|
||||
def index
|
||||
@categories = Category.all
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
def show; end
|
||||
|
||||
def create
|
||||
authorize Category
|
||||
@ -39,11 +42,12 @@ class API::CategoriesController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
def set_category
|
||||
@category = Category.find(params[:id])
|
||||
end
|
||||
|
||||
def category_params
|
||||
params.require(:category).permit(:name)
|
||||
end
|
||||
def set_category
|
||||
@category = Category.find(params[:id])
|
||||
end
|
||||
|
||||
def category_params
|
||||
params.require(:category).permit(:name)
|
||||
end
|
||||
end
|
||||
|
@ -1,13 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Component
|
||||
# Components are used in Projects
|
||||
class API::ComponentsController < API::ApiController
|
||||
before_action :authenticate_user!, except: [:index, :show]
|
||||
before_action :set_component, only: [:show, :update, :destroy]
|
||||
before_action :authenticate_user!, except: %i[index show]
|
||||
before_action :set_component, only: %i[show update destroy]
|
||||
|
||||
def index
|
||||
@components = Component.all
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
def show; end
|
||||
|
||||
def create
|
||||
authorize Component
|
||||
@ -35,11 +38,12 @@ class API::ComponentsController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
def set_component
|
||||
@component = Component.find(params[:id])
|
||||
end
|
||||
|
||||
def component_params
|
||||
params.require(:component).permit(:name)
|
||||
end
|
||||
def set_component
|
||||
@component = Component.find(params[:id])
|
||||
end
|
||||
|
||||
def component_params
|
||||
params.require(:component).permit(:name)
|
||||
end
|
||||
end
|
||||
|
@ -1,13 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Coupon
|
||||
# Coupons are used in payments
|
||||
class API::CouponsController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
before_action :set_coupon, only: [:show, :update, :destroy]
|
||||
before_action :set_coupon, only: %i[show update destroy]
|
||||
|
||||
def index
|
||||
@coupons = Coupon.all
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
def show; end
|
||||
|
||||
def create
|
||||
authorize Coupon
|
||||
@ -22,18 +25,18 @@ class API::CouponsController < API::ApiController
|
||||
def validate
|
||||
@coupon = Coupon.find_by(code: params[:code])
|
||||
if @coupon.nil?
|
||||
render json: {status: 'rejected'}, status: :not_found
|
||||
render json: { status: 'rejected' }, status: :not_found
|
||||
else
|
||||
if !current_user.admin?
|
||||
_user_id = current_user.id
|
||||
else
|
||||
_user_id = params[:user_id]
|
||||
end
|
||||
_user_id = if !current_user.admin?
|
||||
current_user.id
|
||||
else
|
||||
params[:user_id]
|
||||
end
|
||||
|
||||
amount = params[:amount].to_f * 100.0
|
||||
status = @coupon.status(_user_id, amount)
|
||||
if status != 'active'
|
||||
render json: {status: status}, status: :unprocessable_entity
|
||||
render json: { status: status }, status: :unprocessable_entity
|
||||
else
|
||||
render :validate, status: :ok, location: @coupon
|
||||
end
|
||||
@ -62,18 +65,17 @@ class API::CouponsController < API::ApiController
|
||||
authorize Coupon
|
||||
|
||||
@coupon = Coupon.find_by(code: params[:coupon_code])
|
||||
if @coupon.nil?
|
||||
render json: {error: "no coupon with code #{params[:coupon_code]}"}, status: :not_found
|
||||
else
|
||||
if @coupon.send_to(params[:user_id])
|
||||
render :show, status: :ok, location: @coupon
|
||||
else
|
||||
render json: @coupon.errors, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
if @coupon.nil?
|
||||
render json: { error: "no coupon with code #{params[:coupon_code]}" }, status: :not_found
|
||||
elsif @coupon.send_to(params[:user_id])
|
||||
render :show, status: :ok, location: @coupon
|
||||
else
|
||||
render json: @coupon.errors, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_coupon
|
||||
@coupon = Coupon.find(params[:id])
|
||||
end
|
||||
@ -85,7 +87,8 @@ class API::CouponsController < API::ApiController
|
||||
@parameters = params
|
||||
@parameters[:coupon][:amount_off] = @parameters[:coupon][:amount_off].to_f * 100.0 if @parameters[:coupon][:amount_off]
|
||||
|
||||
@parameters = @parameters.require(:coupon).permit(:name, :code, :percent_off, :amount_off, :validity_per_user, :valid_until, :max_usages, :active)
|
||||
@parameters = @parameters.require(:coupon).permit(:name, :code, :percent_off, :amount_off, :validity_per_user, :valid_until,
|
||||
:max_usages, :active)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,14 +1,18 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Credit
|
||||
# Credits are used to give free reservations to users
|
||||
class API::CreditsController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
before_action :set_credit, only: [:show, :update, :destroy]
|
||||
before_action :set_credit, only: %i[show update destroy]
|
||||
|
||||
def index
|
||||
authorize Credit
|
||||
if params
|
||||
@credits = Credit.includes(:creditable).where(params.permit(:creditable_type))
|
||||
else
|
||||
@credits = Credit.includes(:creditable).all
|
||||
end
|
||||
@credits = if params
|
||||
Credit.includes(:creditable).where(params.permit(:creditable_type))
|
||||
else
|
||||
Credit.includes(:creditable).all
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
@ -37,11 +41,12 @@ class API::CreditsController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
def set_credit
|
||||
@credit = Credit.find(params[:id])
|
||||
end
|
||||
|
||||
def credit_params
|
||||
params.require(:credit).permit!
|
||||
end
|
||||
def set_credit
|
||||
@credit = Credit.find(params[:id])
|
||||
end
|
||||
|
||||
def credit_params
|
||||
params.require(:credit).permit!
|
||||
end
|
||||
end
|
||||
|
@ -1,10 +1,10 @@
|
||||
class API::CustomAssetsController < API::ApiController
|
||||
before_action :authenticate_user!, only: [:index, :update, :create, :destroy]
|
||||
before_action :set_custom_asset, only: [:show, :update, :destroy]
|
||||
# frozen_string_literal: true
|
||||
|
||||
def index
|
||||
#TODO GET /api/custom_assets/
|
||||
end
|
||||
# API Controller for resources of type CustomAsset
|
||||
# CustomAssets are used in settings
|
||||
class API::CustomAssetsController < API::ApiController
|
||||
before_action :authenticate_user!, only: %i[index update create destroy]
|
||||
before_action :set_custom_asset, only: %i[show update destroy]
|
||||
|
||||
# PUT /api/custom_assets/1/
|
||||
def update
|
||||
@ -28,14 +28,10 @@ class API::CustomAssetsController < API::ApiController
|
||||
end
|
||||
|
||||
# GET /api/custom_assets/1/
|
||||
def show
|
||||
end
|
||||
|
||||
def destroy
|
||||
#TODO DELETE /api/custom_assets/1/
|
||||
end
|
||||
def show; end
|
||||
|
||||
private
|
||||
|
||||
def set_custom_asset
|
||||
@custom_asset = CustomAsset.find_by(name: params[:id])
|
||||
end
|
||||
@ -45,4 +41,4 @@ class API::CustomAssetsController < API::ApiController
|
||||
params.required(:custom_asset).permit(:name, custom_asset_file_attributes: [:attachment])
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -1,13 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type EventTheme
|
||||
# EventTheme are used to classify Events
|
||||
class API::EventThemesController < API::ApiController
|
||||
before_action :authenticate_user!, except: [:index]
|
||||
before_action :set_event_theme, only: [:show, :update, :destroy]
|
||||
before_action :set_event_theme, only: %i[show update destroy]
|
||||
|
||||
def index
|
||||
@event_themes = EventTheme.all
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
def show; end
|
||||
|
||||
def create
|
||||
authorize EventTheme
|
||||
@ -39,6 +42,7 @@ class API::EventThemesController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_event_theme
|
||||
@event_theme = EventTheme.find(params[:id])
|
||||
end
|
||||
|
@ -1,5 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Event
|
||||
class API::EventsController < API::ApiController
|
||||
before_action :set_event, only: [:show, :update, :destroy]
|
||||
before_action :set_event, only: %i[show update destroy]
|
||||
|
||||
def index
|
||||
@events = policy_scope(Event)
|
||||
@ -11,17 +14,17 @@ class API::EventsController < API::ApiController
|
||||
@events = @events.joins(:event_themes).where('event_themes.id = :theme', theme: params[:theme_id]) if params[:theme_id]
|
||||
@events = @events.where('age_range_id = :age_range', age_range: params[:age_range_id]) if params[:age_range_id]
|
||||
|
||||
if current_user and current_user.admin?
|
||||
case params[:scope]
|
||||
when 'future'
|
||||
@events = @events.where('availabilities.start_at >= ?', Time.now).order('availabilities.start_at DESC')
|
||||
when 'future_asc'
|
||||
@events = @events.where('availabilities.start_at >= ?', Time.now).order('availabilities.start_at ASC')
|
||||
when 'passed'
|
||||
@events = @events.where('availabilities.start_at < ?', Time.now).order('availabilities.start_at DESC')
|
||||
else
|
||||
@events = @events.order('availabilities.start_at DESC')
|
||||
end
|
||||
if current_user&.admin?
|
||||
@events = case params[:scope]
|
||||
when 'future'
|
||||
@events.where('availabilities.start_at >= ?', Time.now).order('availabilities.start_at DESC')
|
||||
when 'future_asc'
|
||||
@events.where('availabilities.start_at >= ?', Time.now).order('availabilities.start_at ASC')
|
||||
when 'passed'
|
||||
@events.where('availabilities.start_at < ?', Time.now).order('availabilities.start_at DESC')
|
||||
else
|
||||
@events.order('availabilities.start_at DESC')
|
||||
end
|
||||
end
|
||||
|
||||
# paginate
|
||||
@ -38,8 +41,7 @@ class API::EventsController < API::ApiController
|
||||
.limit(limit)
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
def show; end
|
||||
|
||||
def create
|
||||
authorize Event
|
||||
@ -61,9 +63,10 @@ class API::EventsController < API::ApiController
|
||||
end
|
||||
rescue ActiveRecord::RecordNotDestroyed => e
|
||||
if e.record.class.name == 'EventPriceCategory'
|
||||
render json: {error: ["#{e.record.price_category.name}: #{t('events.error_deleting_reserved_price')}"]}, status: :unprocessable_entity
|
||||
render json: { error: ["#{e.record.price_category.name}: #{t('events.error_deleting_reserved_price')}"] },
|
||||
status: :unprocessable_entity
|
||||
else
|
||||
render json: {error: [t('events.other_error')]}, status: :unprocessable_entity
|
||||
render json: { error: [t('events.other_error')] }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
@ -79,48 +82,22 @@ class API::EventsController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
# Use callbacks to share common setup or constraints between actions.
|
||||
def set_event
|
||||
@event = Event.find(params[:id])
|
||||
end
|
||||
|
||||
# Never trust parameters from the scary internet, only allow the white list through.
|
||||
def event_params
|
||||
# handle general properties
|
||||
event_preparams = params.required(:event).permit(:title, :description, :start_date, :start_time, :end_date, :end_time,
|
||||
:amount, :nb_total_places, :availability_id,
|
||||
:all_day, :recurrence, :recurrence_end_at, :category_id, :event_theme_ids,
|
||||
:age_range_id, event_theme_ids: [],
|
||||
event_image_attributes: [:attachment],
|
||||
event_files_attributes: [:id, :attachment, :_destroy],
|
||||
event_price_categories_attributes: [:id, :price_category_id, :amount, :_destroy]
|
||||
)
|
||||
# handle dates & times (whole-day events or not, maybe during many days)
|
||||
start_date = Time.zone.parse(event_preparams[:start_date])
|
||||
end_date = Time.zone.parse(event_preparams[:end_date])
|
||||
start_time = Time.parse(event_preparams[:start_time]) if event_preparams[:start_time]
|
||||
end_time = Time.parse(event_preparams[:end_time]) if event_preparams[:end_time]
|
||||
if event_preparams[:all_day] == 'true'
|
||||
start_at = DateTime.new(start_date.year, start_date.month, start_date.day, 0, 0, 0, start_date.zone)
|
||||
end_at = DateTime.new(end_date.year, end_date.month, end_date.day, 23, 59, 59, end_date.zone)
|
||||
else
|
||||
start_at = DateTime.new(start_date.year, start_date.month, start_date.day, start_time.hour, start_time.min, start_time.sec, start_date.zone)
|
||||
end_at = DateTime.new(end_date.year, end_date.month, end_date.day, end_time.hour, end_time.min, end_time.sec, end_date.zone)
|
||||
end
|
||||
event_preparams.merge!(availability_attributes: {id: event_preparams[:availability_id], start_at: start_at, end_at: end_at, available_type: 'event'})
|
||||
.except!(:start_date, :end_date, :start_time, :end_time, :all_day)
|
||||
# convert main price to centimes
|
||||
event_preparams.merge!(amount: (event_preparams[:amount].to_f * 100 if event_preparams[:amount].present?))
|
||||
# delete non-complete "other" prices and convert them to centimes
|
||||
unless event_preparams[:event_price_categories_attributes].nil?
|
||||
event_preparams[:event_price_categories_attributes].delete_if { |price_cat| price_cat[:price_category_id].empty? or price_cat[:amount].empty? }
|
||||
event_preparams[:event_price_categories_attributes].each do |price_cat|
|
||||
price_cat[:amount] = price_cat[:amount].to_f * 100
|
||||
end
|
||||
end
|
||||
# return the resulting params object
|
||||
event_preparams
|
||||
end
|
||||
|
||||
# Use callbacks to share common setup or constraints between actions.
|
||||
def set_event
|
||||
@event = Event.find(params[:id])
|
||||
end
|
||||
|
||||
# Never trust parameters from the scary internet, only allow the white list through.
|
||||
def event_params
|
||||
# handle general properties
|
||||
event_preparams = params.required(:event).permit(:title, :description, :start_date, :start_time, :end_date, :end_time,
|
||||
:amount, :nb_total_places, :availability_id, :all_day, :recurrence,
|
||||
:recurrence_end_at, :category_id, :event_theme_ids, :age_range_id,
|
||||
event_theme_ids: [],
|
||||
event_image_attributes: [:attachment],
|
||||
event_files_attributes: %i[id attachment_destroy],
|
||||
event_price_categories_attributes: %i[id price_category_id amount _destroy])
|
||||
EventService.process_params(event_preparams)
|
||||
end
|
||||
end
|
||||
|
@ -1,3 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Export
|
||||
# Export are used to download data tables in offline files
|
||||
class API::ExportsController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
before_action :set_export, only: [:download]
|
||||
@ -6,7 +10,9 @@ class API::ExportsController < API::ApiController
|
||||
authorize @export
|
||||
|
||||
if FileTest.exist?(@export.file)
|
||||
send_file File.join(Rails.root, @export.file), :type => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', :disposition => 'attachment'
|
||||
send_file File.join(Rails.root, @export.file),
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
disposition: 'attachment'
|
||||
else
|
||||
render text: I18n.t('errors.messages.export_not_found'), status: :not_found
|
||||
end
|
||||
@ -15,38 +21,39 @@ class API::ExportsController < API::ApiController
|
||||
def status
|
||||
authorize Export
|
||||
|
||||
export = Export.where({category: params[:category], export_type: params[:type], query: params[:query], key: params[:key]})
|
||||
export = Export.where(category: params[:category], export_type: params[:type], query: params[:query], key: params[:key])
|
||||
|
||||
if params[:category] === 'users'
|
||||
if params[:category] == 'users'
|
||||
case params[:type]
|
||||
when 'subscriptions'
|
||||
export = export.where('created_at > ?', Subscription.maximum('updated_at'))
|
||||
when 'reservations'
|
||||
export = export.where('created_at > ?', Reservation.maximum('updated_at'))
|
||||
when 'members'
|
||||
export = export.where('created_at > ?', User.with_role(:member).maximum('updated_at'))
|
||||
else
|
||||
raise ArgumentError, "Unknown export users/#{params[:type]}"
|
||||
when 'subscriptions'
|
||||
export = export.where('created_at > ?', Subscription.maximum('updated_at'))
|
||||
when 'reservations'
|
||||
export = export.where('created_at > ?', Reservation.maximum('updated_at'))
|
||||
when 'members'
|
||||
export = export.where('created_at > ?', User.with_role(:member).maximum('updated_at'))
|
||||
else
|
||||
raise ArgumentError, "Unknown export users/#{params[:type]}"
|
||||
end
|
||||
elsif params[:category] === 'availabilities'
|
||||
elsif params[:category] == 'availabilities'
|
||||
case params[:type]
|
||||
when 'index'
|
||||
export = export.where('created_at > ?', Availability.maximum('updated_at'))
|
||||
else
|
||||
raise ArgumentError, "Unknown type availabilities/#{params[:type]}"
|
||||
when 'index'
|
||||
export = export.where('created_at > ?', Availability.maximum('updated_at'))
|
||||
else
|
||||
raise ArgumentError, "Unknown type availabilities/#{params[:type]}"
|
||||
end
|
||||
end
|
||||
export = export.last
|
||||
|
||||
if export.nil? || !FileTest.exist?(export.file)
|
||||
render json: {exists: false, id: nil}, status: :ok
|
||||
render json: { exists: false, id: nil }, status: :ok
|
||||
else
|
||||
render json: {exists: true, id: export.id}, status: :ok
|
||||
render json: { exists: true, id: export.id }, status: :ok
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_export
|
||||
@export = Export.find(params[:id])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,16 +1,19 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller to wrap social networks public feeds
|
||||
class API::FeedsController < API::ApiController
|
||||
|
||||
respond_to :json
|
||||
|
||||
def twitter_timelines
|
||||
if params
|
||||
limit = params[:limit]
|
||||
else
|
||||
limit = 3
|
||||
end
|
||||
limit = if params
|
||||
params[:limit]
|
||||
else
|
||||
3
|
||||
end
|
||||
from_account = Setting.find_by(name: 'twitter_name').try(:value) || ENV['TWITTER_NAME']
|
||||
begin
|
||||
@tweet_news = Feed.twitter.user_timeline(from_account, {count: limit})
|
||||
@tweet_news = Feed.twitter.user_timeline(from_account, count: limit)
|
||||
rescue Twitter::Error::BadRequest => e
|
||||
STDERR.puts "[WARNING] Unable to retrieve the twitter feed, please check your ENV configuration. Details: #{e.message}"
|
||||
render status: :no_content
|
||||
|
@ -1,12 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Group
|
||||
# Groups are used for categorizing Users
|
||||
class API::GroupsController < API::ApiController
|
||||
before_action :authenticate_user!, except: :index
|
||||
|
||||
def index
|
||||
if current_user and current_user.admin?
|
||||
@groups = Group.all
|
||||
else
|
||||
@groups = Group.where.not(slug: 'admins')
|
||||
end
|
||||
@groups = if current_user&.admin?
|
||||
Group.all
|
||||
else
|
||||
Group.where.not(slug: 'admins')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -39,7 +43,7 @@ class API::GroupsController < API::ApiController
|
||||
|
||||
private
|
||||
|
||||
def group_params
|
||||
params.require(:group).permit(:name, :disabled)
|
||||
end
|
||||
def group_params
|
||||
params.require(:group).permit(:name, :disabled)
|
||||
end
|
||||
end
|
||||
|
@ -1,13 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Licence
|
||||
# Licenses are used in Projects
|
||||
class API::LicencesController < API::ApiController
|
||||
before_action :authenticate_user!, except: [:index, :show]
|
||||
before_action :set_licence, only: [:show, :update, :destroy]
|
||||
before_action :authenticate_user!, except: %i[index show]
|
||||
before_action :set_licence, only: %i[show update destroy]
|
||||
|
||||
def index
|
||||
@licences = Licence.all
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
def show; end
|
||||
|
||||
def create
|
||||
authorize Licence
|
||||
@ -35,11 +38,12 @@ class API::LicencesController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
def set_licence
|
||||
@licence = Licence.find(params[:id])
|
||||
end
|
||||
|
||||
def licence_params
|
||||
params.require(:licence).permit(:name, :description)
|
||||
end
|
||||
def set_licence
|
||||
@licence = Licence.find(params[:id])
|
||||
end
|
||||
|
||||
def licence_params
|
||||
params.require(:licence).permit(:name, :description)
|
||||
end
|
||||
end
|
||||
|
@ -1,15 +1,18 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Machine
|
||||
class API::MachinesController < API::ApiController
|
||||
before_action :authenticate_user!, except: [:index, :show]
|
||||
before_action :set_machine, only: [:update, :destroy]
|
||||
before_action :authenticate_user!, except: %i[index show]
|
||||
before_action :set_machine, only: %i[update destroy]
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
sort_by = Setting.find_by(name: 'machines_sort_by').value || 'default'
|
||||
if sort_by === 'default'
|
||||
@machines = Machine.includes(:machine_image, :plans)
|
||||
else
|
||||
@machines = Machine.includes(:machine_image, :plans).order(sort_by)
|
||||
end
|
||||
@machines = if sort_by == 'default'
|
||||
Machine.includes(:machine_image, :plans)
|
||||
else
|
||||
Machine.includes(:machine_image, :plans).order(sort_by)
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
@ -42,22 +45,14 @@ class API::MachinesController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
def set_machine
|
||||
@machine = Machine.find(params[:id])
|
||||
end
|
||||
|
||||
def machine_params
|
||||
params.require(:machine).permit(:name, :description, :spec, :disabled, :plan_ids, plan_ids: [], machine_image_attributes: [:attachment],
|
||||
machine_files_attributes: [:id, :attachment, :_destroy])
|
||||
end
|
||||
def set_machine
|
||||
@machine = Machine.find(params[:id])
|
||||
end
|
||||
|
||||
def is_reserved(start_at, reservations)
|
||||
is_reserved = false
|
||||
reservations.each do |r|
|
||||
r.slots.each do |s|
|
||||
is_reserved = true if s.start_at == start_at
|
||||
end
|
||||
end
|
||||
is_reserved
|
||||
end
|
||||
def machine_params
|
||||
params.require(:machine).permit(:name, :description, :spec, :disabled, :plan_ids,
|
||||
plan_ids: [], machine_image_attributes: [:attachment],
|
||||
machine_files_attributes: %i[id attachment _destroy])
|
||||
end
|
||||
end
|
||||
|
@ -1,15 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type User with role 'member'
|
||||
class API::MembersController < API::ApiController
|
||||
before_action :authenticate_user!, except: [:last_subscribed]
|
||||
before_action :set_member, only: [:update, :destroy, :merge]
|
||||
before_action :set_member, only: %i[update destroy merge]
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
@requested_attributes = params[:requested_attributes]
|
||||
@query = policy_scope(User)
|
||||
|
||||
unless params[:page].nil? and params[:size].nil?
|
||||
@query = @query.page(params[:page].to_i).per(params[:size].to_i)
|
||||
end
|
||||
@query = @query.page(params[:page].to_i).per(params[:size].to_i) unless params[:page].nil? && params[:size].nil?
|
||||
|
||||
# remove unmerged profiles from list
|
||||
@members = @query.to_a
|
||||
@ -17,7 +18,11 @@ class API::MembersController < API::ApiController
|
||||
end
|
||||
|
||||
def last_subscribed
|
||||
@query = User.active.with_role(:member).includes(profile: [:user_avatar]).where('is_allow_contact = true AND confirmed_at IS NOT NULL').order('created_at desc').limit(params[:last])
|
||||
@query = User.active.with_role(:member)
|
||||
.includes(profile: [:user_avatar])
|
||||
.where('is_allow_contact = true AND confirmed_at IS NOT NULL')
|
||||
.order('created_at desc')
|
||||
.limit(params[:last])
|
||||
|
||||
# remove unmerged profiles from list
|
||||
@members = @query.to_a
|
||||
@ -34,27 +39,11 @@ class API::MembersController < API::ApiController
|
||||
|
||||
def create
|
||||
authorize User
|
||||
if !user_params[:password] and !user_params[:password_confirmation]
|
||||
generated_password = Devise.friendly_token.first(8)
|
||||
@member = User.new(user_params.merge(password: generated_password).permit!)
|
||||
else
|
||||
@member = User.new(user_params.permit!)
|
||||
end
|
||||
|
||||
@member = User.new(user_params.permit!)
|
||||
members_service = Members::MembersService.new(@member)
|
||||
|
||||
# if the user is created by an admin and the authentication is made through an SSO, generate a migration token
|
||||
if current_user.admin? and AuthProvider.active.providable_type != DatabaseProvider.name
|
||||
@member.generate_auth_migration_token
|
||||
end
|
||||
|
||||
if @member.save
|
||||
@member.generate_subscription_invoice
|
||||
@member.send_confirmation_instructions
|
||||
if !user_params[:password] and !user_params[:password_confirmation]
|
||||
UsersMailer.delay.notify_user_account_created(@member, generated_password)
|
||||
else
|
||||
UsersMailer.delay.notify_user_account_created(@member, user_params[:password])
|
||||
end
|
||||
if members_service.create(current_user, user_params)
|
||||
render :show, status: :created, location: member_path(@member)
|
||||
else
|
||||
render json: @member.errors, status: :unprocessable_entity
|
||||
@ -63,21 +52,14 @@ class API::MembersController < API::ApiController
|
||||
|
||||
def update
|
||||
authorize @member
|
||||
members_service = MembersService.new(@member)
|
||||
members_service = Members::MembersService.new(@member)
|
||||
|
||||
if user_params[:group_id] && @member.group_id != user_params[:group_id].to_i && !@member.subscribed_plan.nil?
|
||||
# here a group change is requested but unprocessable, handle the exception
|
||||
@member.errors[:group_id] = t('members.unable_to_change_the_group_while_a_subscription_is_running')
|
||||
render json: @member.errors, status: :unprocessable_entity
|
||||
if members_service.update(user_params)
|
||||
# Update password without logging out
|
||||
sign_in(@member, bypass: true) unless current_user.id != params[:id].to_i
|
||||
render :show, status: :ok, location: member_path(@member)
|
||||
else
|
||||
# otherwise, run the user update
|
||||
if members_service.update(user_params)
|
||||
# Update password without logging out
|
||||
sign_in(@member, bypass: true) unless current_user.id != params[:id].to_i
|
||||
render :show, status: :ok, location: member_path(@member)
|
||||
else
|
||||
render json: @member.errors, status: :unprocessable_entity
|
||||
end
|
||||
render json: @member.errors, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
@ -92,9 +74,11 @@ class API::MembersController < API::ApiController
|
||||
def export_subscriptions
|
||||
authorize :export
|
||||
|
||||
export = Export.where(category:'users', export_type: 'subscriptions').where('created_at > ?', Subscription.maximum('updated_at')).last
|
||||
export = Export.where(category: 'users', export_type: 'subscriptions')
|
||||
.where('created_at > ?', Subscription.maximum('updated_at'))
|
||||
.last
|
||||
if export.nil? || !FileTest.exist?(export.file)
|
||||
@export = Export.new(category:'users', export_type: 'subscriptions', user: current_user)
|
||||
@export = Export.new(category: 'users', export_type: 'subscriptions', user: current_user)
|
||||
if @export.save
|
||||
render json: { export_id: @export.id }, status: :ok
|
||||
else
|
||||
@ -111,7 +95,7 @@ class API::MembersController < API::ApiController
|
||||
def export_reservations
|
||||
authorize :export
|
||||
|
||||
export = Export.where(category:'users', export_type: 'reservations')
|
||||
export = Export.where(category: 'users', export_type: 'reservations')
|
||||
.where('created_at > ?', Reservation.maximum('updated_at'))
|
||||
.last
|
||||
if export.nil? || !FileTest.exist?(export.file)
|
||||
@ -131,11 +115,11 @@ class API::MembersController < API::ApiController
|
||||
def export_members
|
||||
authorize :export
|
||||
|
||||
export = Export.where(category:'users', export_type: 'members')
|
||||
export = Export.where(category: 'users', export_type: 'members')
|
||||
.where('created_at > ?', User.with_role(:member).maximum('updated_at'))
|
||||
.last
|
||||
if export.nil? || !FileTest.exist?(export.file)
|
||||
@export = Export.new(category:'users', export_type: 'members', user: current_user)
|
||||
@export = Export.new(category: 'users', export_type: 'members', user: current_user)
|
||||
if @export.save
|
||||
render json: { export_id: @export.id }, status: :ok
|
||||
else
|
||||
@ -148,16 +132,15 @@ class API::MembersController < API::ApiController
|
||||
end
|
||||
end
|
||||
|
||||
# the user is querying to be mapped to his already existing account
|
||||
def merge
|
||||
authorize @member
|
||||
|
||||
# here the user query to be mapped to his already existing account
|
||||
|
||||
token = params.require(:user).permit(:auth_token)[:auth_token]
|
||||
token = token_param
|
||||
|
||||
@account = User.find_by(auth_token: token)
|
||||
if @account
|
||||
members_service = MembersService.new(@account)
|
||||
members_service = Members::MembersService.new(@account)
|
||||
begin
|
||||
if members_service.merge_from_sso(@member)
|
||||
@member = @account
|
||||
@ -168,7 +151,8 @@ class API::MembersController < API::ApiController
|
||||
render json: @member.errors, status: :unprocessable_entity
|
||||
end
|
||||
rescue DuplicateIndexError => error
|
||||
render json: { error: t('members.please_input_the_authentication_code_sent_to_the_address', EMAIL: error.message) }, status: :unprocessable_entity
|
||||
render json: { error: t('members.please_input_the_authentication_code_sent_to_the_address', EMAIL: error.message) },
|
||||
status: :unprocessable_entity
|
||||
end
|
||||
else
|
||||
render json: { error: t('members.your_authentication_code_is_not_valid') }, status: :unprocessable_entity
|
||||
@ -178,67 +162,17 @@ class API::MembersController < API::ApiController
|
||||
def list
|
||||
authorize User
|
||||
|
||||
p = params.require(:query).permit(:search, :order_by, :page, :size)
|
||||
render json: { error: 'page must be an integer' }, status: :unprocessable_entity and return unless query_params[:page].is_a? Integer
|
||||
render json: { error: 'size must be an integer' }, status: :unprocessable_entity and return unless query_params[:size].is_a? Integer
|
||||
|
||||
|
||||
render json: {error: 'page must be an integer'}, status: :unprocessable_entity unless p[:page].is_a? Integer
|
||||
|
||||
render json: {error: 'size must be an integer'}, status: :unprocessable_entity unless p[:size].is_a? Integer
|
||||
|
||||
|
||||
direction = (p[:order_by][0] == '-' ? 'DESC' : 'ASC')
|
||||
order_key = (p[:order_by][0] == '-' ? p[:order_by][1, p[:order_by].size] : p[:order_by])
|
||||
|
||||
order_key = case order_key
|
||||
when 'last_name'
|
||||
'profiles.last_name'
|
||||
when 'first_name'
|
||||
'profiles.first_name'
|
||||
when 'email'
|
||||
'users.email'
|
||||
when 'phone'
|
||||
'profiles.phone'
|
||||
when 'group'
|
||||
'groups.name'
|
||||
when 'plan'
|
||||
'plans.base_name'
|
||||
else
|
||||
'users.id'
|
||||
end
|
||||
|
||||
@query = User.includes(:profile, :group, :subscriptions)
|
||||
.joins(:profile, :group, :roles, 'LEFT JOIN "subscriptions" ON "subscriptions"."user_id" = "users"."id" LEFT JOIN "plans" ON "plans"."id" = "subscriptions"."plan_id"')
|
||||
.where("users.is_active = 'true' AND roles.name = 'member'")
|
||||
.order("#{order_key} #{direction}")
|
||||
.page(p[:page])
|
||||
.per(p[:size])
|
||||
|
||||
# ILIKE => PostgreSQL case-insensitive LIKE
|
||||
@query = @query.where('profiles.first_name ILIKE :search OR profiles.last_name ILIKE :search OR profiles.phone ILIKE :search OR email ILIKE :search OR groups.name ILIKE :search OR plans.base_name ILIKE :search', search: "%#{p[:search]}%") if p[:search].size > 0
|
||||
|
||||
@members = @query.to_a
|
||||
query = Members::ListService.list(query_params)
|
||||
@max_members = query.except(:offset, :limit, :order).count
|
||||
@members = query.to_a
|
||||
|
||||
end
|
||||
|
||||
def search
|
||||
@members = User.includes(:profile)
|
||||
.joins(:profile, :roles, 'LEFT JOIN "subscriptions" ON "subscriptions"."user_id" = "users"."id"')
|
||||
.where("users.is_active = 'true' AND roles.name = 'member'")
|
||||
.where("lower(f_unaccent(profiles.first_name)) ~ regexp_replace(:search, E'\\\\s+', '|') OR lower(f_unaccent(profiles.last_name)) ~ regexp_replace(:search, E'\\\\s+', '|')", search: params[:query].downcase)
|
||||
|
||||
if current_user.member?
|
||||
# non-admin can only retrieve users with "public profiles"
|
||||
@members = @members.where("users.is_allow_contact = 'true'")
|
||||
else
|
||||
# only admins have the ability to filter by subscription
|
||||
if params[:subscription] === 'true'
|
||||
@members = @members.where('subscriptions.id IS NOT NULL AND subscriptions.expired_at >= :now', now: Date.today.to_s)
|
||||
elsif params[:subscription] === 'false'
|
||||
@members = @members.where('subscriptions.id IS NULL OR subscriptions.expired_at < :now', now: Date.today.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
@members = @members.to_a
|
||||
@members = Members::ListService.search(current_user, params[:query], params[:subscription])
|
||||
end
|
||||
|
||||
def mapping
|
||||
@ -281,4 +215,12 @@ class API::MembersController < API::ApiController
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
def token_param
|
||||
params.require(:user).permit(:auth_token)[:auth_token]
|
||||
end
|
||||
|
||||
def query_params
|
||||
params.require(:query).permit(:search, :order_by, :page, :size)
|
||||
end
|
||||
end
|
||||
|
@ -1,3 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Notification
|
||||
# Notifications are scoped by user
|
||||
class API::NotificationsController < API::ApiController
|
||||
include NotifyWith::NotificationsApi
|
||||
before_action :authenticate_user!
|
||||
@ -12,8 +16,8 @@ class API::NotificationsController < API::ApiController
|
||||
break unless delete_obsoletes(@notifications)
|
||||
end
|
||||
@totals = {
|
||||
total: current_user.notifications.count,
|
||||
unread: current_user.notifications.where(is_read: false).count
|
||||
total: current_user.notifications.count,
|
||||
unread: current_user.notifications.where(is_read: false).count
|
||||
}
|
||||
render :index
|
||||
end
|
||||
@ -25,17 +29,19 @@ class API::NotificationsController < API::ApiController
|
||||
break unless delete_obsoletes(@notifications)
|
||||
end
|
||||
@totals = {
|
||||
total: current_user.notifications.count,
|
||||
unread: current_user.notifications.where(is_read: false).count
|
||||
total: current_user.notifications.count,
|
||||
unread: current_user.notifications.where(is_read: false).count
|
||||
}
|
||||
render :index
|
||||
end
|
||||
|
||||
def polling
|
||||
@notifications = current_user.notifications.where('is_read = false AND created_at >= :date', date: params[:last_poll]).order('created_at DESC')
|
||||
@notifications = current_user.notifications
|
||||
.where('is_read = false AND created_at >= :date', date: params[:last_poll])
|
||||
.order('created_at DESC')
|
||||
@totals = {
|
||||
total: current_user.notifications.count,
|
||||
unread: current_user.notifications.where(is_read: false).count
|
||||
total: current_user.notifications.count,
|
||||
unread: current_user.notifications.where(is_read: false).count
|
||||
}
|
||||
render :index
|
||||
end
|
||||
@ -45,7 +51,7 @@ class API::NotificationsController < API::ApiController
|
||||
def delete_obsoletes(notifications)
|
||||
cleaned = false
|
||||
notifications.each do |n|
|
||||
if !Module.const_get(n.attached_object_type) or !n.attached_object
|
||||
if !Module.const_get(n.attached_object_type) || !n.attached_object
|
||||
n.destroy!
|
||||
cleaned = true
|
||||
end
|
||||
|
@ -1,3 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type OpenAPI::Client
|
||||
# OpenAPI::Clients are used to allow access to the public API
|
||||
class API::OpenAPIClientsController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
|
||||
@ -5,7 +9,7 @@ class API::OpenAPIClientsController < API::ApiController
|
||||
authorize OpenAPI::Client
|
||||
@clients = OpenAPI::Client.order(:created_at)
|
||||
end
|
||||
# add authorization
|
||||
|
||||
def create
|
||||
@client = OpenAPI::Client.new(client_params)
|
||||
authorize @client
|
||||
@ -40,7 +44,8 @@ class API::OpenAPIClientsController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
def client_params
|
||||
params.require(:open_api_client).permit(:name)
|
||||
end
|
||||
|
||||
def client_params
|
||||
params.require(:open_api_client).permit(:name)
|
||||
end
|
||||
end
|
||||
|
@ -1,11 +1,13 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Openlab::Projects
|
||||
# Openlab::Projects are Projects shared between different instances
|
||||
class API::OpenlabProjectsController < API::ApiController
|
||||
PROJECTS = Openlab::Projects.new
|
||||
|
||||
def index
|
||||
begin
|
||||
render json: PROJECTS.search(params[:q], page: params[:page], per_page: params[:per_page]).response.body
|
||||
rescue StandardError
|
||||
render json: { errors: ['service unavailable'] }
|
||||
end
|
||||
render json: PROJECTS.search(params[:q], page: params[:page], per_page: params[:per_page]).response.body
|
||||
rescue StandardError
|
||||
render json: { errors: ['service unavailable'] }
|
||||
end
|
||||
end
|
||||
|
@ -1,4 +1,9 @@
|
||||
class API::PlansController < API::ApiController
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Plan and PartnerPlan.
|
||||
# Plan are used to define subscription's characteristics.
|
||||
# PartnerPlan is a special kind of plan which send notifications to an external user
|
||||
class API::PlansController < API::ApiController
|
||||
before_action :authenticate_user!, except: [:index]
|
||||
|
||||
def index
|
||||
@ -13,48 +18,19 @@
|
||||
|
||||
def create
|
||||
authorize Plan
|
||||
begin
|
||||
if plan_params[:type] and plan_params[:type] == 'PartnerPlan'
|
||||
|
||||
partner = User.find(params[:plan][:partner_id])
|
||||
unless %w[PartnerPlan Plan].include? plan_params[:type]
|
||||
render json: { error: 'unhandled plan type' }, status: :unprocessable_entity and return
|
||||
end
|
||||
|
||||
if plan_params[:group_id] == 'all'
|
||||
plans = PartnerPlan.create_for_all_groups(plan_params)
|
||||
if plans
|
||||
plans.each { |plan| partner.add_role :partner, plan }
|
||||
render json: { plan_ids: plans.map(&:id) }, status: :created
|
||||
else
|
||||
render status: :unprocessable_entity
|
||||
end
|
||||
type = plan_params[:type]
|
||||
partner = params[:plan][:partner_id].empty? ? nil : User.find(params[:plan][:partner_id])
|
||||
|
||||
else
|
||||
@plan = PartnerPlan.new(plan_params)
|
||||
if @plan.save
|
||||
partner.add_role :partner, @plan
|
||||
render :show, status: :created
|
||||
else
|
||||
render json: @plan.errors, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
else
|
||||
if plan_params[:group_id] == 'all'
|
||||
plans = Plan.create_for_all_groups(plan_params)
|
||||
if plans
|
||||
render json: { plan_ids: plans.map(&:id) }, status: :created
|
||||
else
|
||||
render status: :unprocessable_entity
|
||||
end
|
||||
else
|
||||
@plan = Plan.new(plan_params)
|
||||
if @plan.save
|
||||
render :show, status: :created, location: @plan
|
||||
else
|
||||
render json: @plan.errors, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue Stripe::InvalidRequestError => e
|
||||
render json: {error: e.message}, status: :unprocessable_entity
|
||||
res = PlansService.create(type, partner, plan_params)
|
||||
if res[:errors]
|
||||
render res[:errors], status: :unprocessable_entity
|
||||
else
|
||||
render json: res, status: :created
|
||||
end
|
||||
end
|
||||
|
||||
@ -76,21 +52,25 @@
|
||||
end
|
||||
|
||||
private
|
||||
def plan_params
|
||||
if @parameters
|
||||
@parameters
|
||||
else
|
||||
@parameters = params
|
||||
@parameters[:plan][:amount] = @parameters[:plan][:amount].to_f * 100.0 if @parameters[:plan][:amount]
|
||||
|
||||
def plan_params
|
||||
# parameters caching for performance
|
||||
if @parameters
|
||||
@parameters
|
||||
else
|
||||
@parameters = params
|
||||
@parameters[:plan][:amount] = @parameters[:plan][:amount].to_f * 100.0 if @parameters[:plan][:amount]
|
||||
if @parameters[:plan][:prices_attributes]
|
||||
@parameters[:plan][:prices_attributes] = @parameters[:plan][:prices_attributes].map do |price|
|
||||
{ amount: price[:amount].to_f * 100.0, id: price[:id] }
|
||||
end if @parameters[:plan][:prices_attributes]
|
||||
|
||||
@parameters = @parameters.require(:plan).permit(:base_name, :type, :group_id, :amount, :interval, :interval_count, :is_rolling,
|
||||
:training_credit_nb, :ui_weight, :disabled,
|
||||
plan_file_attributes: [:id, :attachment, :_destroy],
|
||||
prices_attributes: [:id, :amount]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@parameters = @parameters.require(:plan)
|
||||
.permit(:base_name, :type, :group_id, :amount, :interval, :interval_count, :is_rolling,
|
||||
:training_credit_nb, :ui_weight, :disabled,
|
||||
plan_file_attributes: %i[id attachment _destroy],
|
||||
prices_attributes: %i[id amount])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,6 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type PriceCategory
|
||||
# PriceCategories are used in Events
|
||||
class API::PriceCategoriesController < API::ApiController
|
||||
before_action :authenticate_user!, only: [:update, :show, :create, :destroy]
|
||||
before_action :set_price_category, only: [:show, :update, :destroy]
|
||||
before_action :authenticate_user!, only: %i[update show create destroy]
|
||||
before_action :set_price_category, only: %i[show update destroy]
|
||||
|
||||
def index
|
||||
@price_categories = PriceCategory.all
|
||||
@ -15,8 +19,7 @@ class API::PriceCategoriesController < API::ApiController
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
def show; end
|
||||
|
||||
def create
|
||||
authorize PriceCategory
|
||||
@ -38,6 +41,7 @@ class API::PriceCategoriesController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_price_category
|
||||
@price_category = PriceCategory.find(params[:id])
|
||||
end
|
||||
@ -45,4 +49,4 @@ class API::PriceCategoriesController < API::ApiController
|
||||
def price_category_params
|
||||
params.require(:price_category).permit(:name, :conditions)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,3 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Price
|
||||
# Prices are used in reservations (Machine, Space)
|
||||
class API::PricesController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
|
||||
@ -6,29 +10,26 @@ class API::PricesController < API::ApiController
|
||||
@prices = Price.all
|
||||
if params[:priceable_type]
|
||||
@prices = @prices.where(priceable_type: params[:priceable_type])
|
||||
if params[:priceable_id]
|
||||
@prices = @prices.where(priceable_id: params[:priceable_id])
|
||||
end
|
||||
|
||||
@prices = @prices.where(priceable_id: params[:priceable_id]) if params[:priceable_id]
|
||||
end
|
||||
if params[:plan_id]
|
||||
if params[:plan_id] =~ /no|nil|null|undefined/i
|
||||
plan_id = nil
|
||||
else
|
||||
plan_id = params[:plan_id]
|
||||
end
|
||||
plan_id = if params[:plan_id] =~ /no|nil|null|undefined/i
|
||||
nil
|
||||
else
|
||||
params[:plan_id]
|
||||
end
|
||||
@prices = @prices.where(plan_id: plan_id)
|
||||
end
|
||||
if params[:group_id]
|
||||
@prices = @prices.where(group_id: params[:group_id])
|
||||
end
|
||||
@prices = @prices.where(group_id: params[:group_id]) if params[:group_id]
|
||||
end
|
||||
|
||||
def update
|
||||
authorize Price
|
||||
@price = Price.find(params[:id])
|
||||
_price_params = price_params
|
||||
_price_params[:amount] = _price_params[:amount] * 100
|
||||
if @price.update(_price_params)
|
||||
price_parameters = price_params
|
||||
price_parameters[:amount] = price_parameters[:amount] * 100
|
||||
if @price.update(price_parameters)
|
||||
render status: :ok
|
||||
else
|
||||
render status: :unprocessable_entity
|
||||
@ -36,15 +37,22 @@ class API::PricesController < API::ApiController
|
||||
end
|
||||
|
||||
def compute
|
||||
_price_params = compute_price_params
|
||||
price_parameters = compute_price_params
|
||||
# user
|
||||
_user = User.find(_price_params[:user_id])
|
||||
user = User.find(price_parameters[:user_id])
|
||||
# reservable
|
||||
if _price_params[:reservable_id].nil?
|
||||
if price_parameters[:reservable_id].nil?
|
||||
@amount = {elements: nil, total: 0, before_coupon: 0}
|
||||
else
|
||||
_reservable = _price_params[:reservable_type].constantize.find(_price_params[:reservable_id])
|
||||
@amount = Price.compute(current_user.admin?, _user, _reservable, _price_params[:slots_attributes] || [], _price_params[:plan_id], _price_params[:nb_reserve_places], _price_params[:tickets_attributes], coupon_params[:coupon_code])
|
||||
reservable = price_parameters[:reservable_type].constantize.find(price_parameters[:reservable_id])
|
||||
@amount = Price.compute(current_user.admin?,
|
||||
user,
|
||||
reservable,
|
||||
price_parameters[:slots_attributes] || [],
|
||||
price_parameters[:plan_id],
|
||||
price_parameters[:nb_reserve_places],
|
||||
price_parameters[:tickets_attributes],
|
||||
coupon_params[:coupon_code])
|
||||
end
|
||||
|
||||
|
||||
@ -56,14 +64,15 @@ class API::PricesController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def price_params
|
||||
params.require(:price).permit(:amount)
|
||||
end
|
||||
|
||||
def compute_price_params
|
||||
params.require(:reservation).permit(:reservable_id, :reservable_type, :plan_id, :user_id, :nb_reserve_places,
|
||||
tickets_attributes: [:event_price_category_id, :booked],
|
||||
slots_attributes: [:id, :start_at, :end_at, :availability_id, :offered])
|
||||
tickets_attributes: %i[event_price_category_id booked],
|
||||
slots_attributes: %i[id start_at end_at availability_id offered])
|
||||
end
|
||||
|
||||
def coupon_params
|
||||
|
@ -1,5 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for managing Plans prices
|
||||
class API::PricingController < API::ApiController
|
||||
before_action :authenticate_user!, except: [:index, :show]
|
||||
before_action :authenticate_user!, except: %i[index show]
|
||||
|
||||
def index
|
||||
@group_pricing = Group.includes(:plans, :trainings_pricings)
|
||||
@ -10,14 +13,14 @@ class API::PricingController < API::ApiController
|
||||
if params[:training].present?
|
||||
training = Training.find params[:training]
|
||||
params[:group_pricing].each do |group_id, amount|
|
||||
if training
|
||||
group = Group.includes(:plans).find(group_id)
|
||||
if group
|
||||
training_pricing = group.trainings_pricings.find_or_initialize_by(training_id: training.id)
|
||||
training_pricing.amount = amount * 100
|
||||
training_pricing.save
|
||||
end
|
||||
end
|
||||
next unless training
|
||||
|
||||
group = Group.includes(:plans).find(group_id)
|
||||
next unless group
|
||||
|
||||
training_pricing = group.trainings_pricings.find_or_initialize_by(training_id: training.id)
|
||||
training_pricing.amount = amount * 100
|
||||
training_pricing.save
|
||||
end
|
||||
end
|
||||
head 200
|
||||
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Project
|
||||
class API::ProjectsController < API::ApiController
|
||||
before_action :authenticate_user!, except: %i[index show last_published search]
|
||||
before_action :set_project, only: %i[update destroy]
|
||||
|
@ -1,3 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Reservation
|
||||
# Reservations are used for Training, Machine, Space and Event
|
||||
class API::ReservationsController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
before_action :set_reservation, only: %i[show update]
|
||||
@ -46,6 +50,7 @@ class API::ReservationsController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_reservation
|
||||
@reservation = Reservation.find(params[:id])
|
||||
end
|
||||
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Setting
|
||||
class API::SettingsController < API::ApiController
|
||||
before_action :authenticate_user!, only: :update
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Slot
|
||||
# Slots are used to cut Availabilities into reservable slots of ApplicationHelper::SLOT_DURATION minutes
|
||||
class API::SlotsController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
before_action :set_slot, only: [:update, :cancel]
|
||||
before_action :set_slot, only: %i[update cancel]
|
||||
respond_to :json
|
||||
|
||||
def update
|
||||
@ -15,10 +19,11 @@ class API::SlotsController < API::ApiController
|
||||
|
||||
def cancel
|
||||
authorize @slot
|
||||
@slot.update_attributes(:canceled_at => DateTime.now)
|
||||
@slot.update_attributes(canceled_at: DateTime.now)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_slot
|
||||
@slot = Slot.find(params[:id])
|
||||
end
|
||||
|
@ -1,5 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Space
|
||||
class API::SpacesController < API::ApiController
|
||||
before_action :authenticate_user!, except: [:index, :show]
|
||||
before_action :authenticate_user!, except: %i[index show]
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
@ -38,12 +41,14 @@ class API::SpacesController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
def get_space
|
||||
Space.friendly.find(params[:id])
|
||||
end
|
||||
|
||||
def space_params
|
||||
params.require(:space).permit(:name, :description, :characteristics, :default_places, :disabled, space_image_attributes: [:attachment],
|
||||
space_files_attributes: [:id, :attachment, :_destroy])
|
||||
end
|
||||
def get_space
|
||||
Space.friendly.find(params[:id])
|
||||
end
|
||||
|
||||
def space_params
|
||||
params.require(:space).permit(:name, :description, :characteristics, :default_places, :disabled,
|
||||
space_image_attributes: [:attachment],
|
||||
space_files_attributes: %i[id attachment _destroy])
|
||||
end
|
||||
end
|
||||
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Space
|
||||
class API::StatisticsController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
|
||||
@ -6,7 +9,7 @@ class API::StatisticsController < API::ApiController
|
||||
@statistics = StatisticIndex.all
|
||||
end
|
||||
|
||||
%w(account event machine project subscription training user space).each do |path|
|
||||
%w[account event machine project subscription training user space].each do |path|
|
||||
class_eval %{
|
||||
def #{path}
|
||||
authorize :statistic, :#{path}?
|
||||
@ -27,38 +30,50 @@ class API::StatisticsController < API::ApiController
|
||||
# return result
|
||||
render json: results
|
||||
end
|
||||
}, __FILE__, __LINE__ - 20
|
||||
end
|
||||
|
||||
%w[account event machine project subscription training user space].each do |path|
|
||||
class_eval %{
|
||||
def export_#{path}
|
||||
authorize :statistic, :export_#{path}?
|
||||
|
||||
export = Export.where({category:'statistics', export_type: '#{path}', query: params[:body], key: params[:type_key]}).last
|
||||
export = Export.where(category:'statistics', export_type: '#{path}', query: params[:body], key: params[:type_key]).last
|
||||
if export.nil? || !FileTest.exist?(export.file)
|
||||
@export = Export.new({category:'statistics', export_type: '#{path}', user: current_user, query: params[:body], key: params[:type_key]})
|
||||
@export = Export.new(category:'statistics',
|
||||
export_type: '#{path}',
|
||||
user: current_user,
|
||||
query: params[:body],
|
||||
key: params[:type_key])
|
||||
if @export.save
|
||||
render json: {export_id: @export.id}, status: :ok
|
||||
else
|
||||
render json: @export.errors, status: :unprocessable_entity
|
||||
end
|
||||
else
|
||||
send_file File.join(Rails.root, export.file), :type => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', :disposition => 'attachment'
|
||||
send_file File.join(Rails.root, export.file),
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
disposition: 'attachment'
|
||||
end
|
||||
end
|
||||
}
|
||||
}, __FILE__, __LINE__ - 22
|
||||
end
|
||||
|
||||
def export_global
|
||||
authorize :statistic, :export_global?
|
||||
|
||||
export = Export.where({category:'statistics', export_type: 'global', query: params[:body]}).last
|
||||
export = Export.where(category: 'statistics', export_type: 'global', query: params[:body]).last
|
||||
if export.nil? || !FileTest.exist?(export.file)
|
||||
@export = Export.new({category:'statistics', export_type: 'global', user: current_user, query: params[:body]})
|
||||
@export = Export.new(category: 'statistics', export_type: 'global', user: current_user, query: params[:body])
|
||||
if @export.save
|
||||
render json: {export_id: @export.id}, status: :ok
|
||||
render json: { export_id: @export.id }, status: :ok
|
||||
else
|
||||
render json: @export.errors, status: :unprocessable_entity
|
||||
end
|
||||
else
|
||||
send_file File.join(Rails.root, export.file), :type => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', :disposition => 'attachment'
|
||||
send_file File.join(Rails.root, export.file),
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
disposition: 'attachment'
|
||||
end
|
||||
end
|
||||
|
||||
@ -68,5 +83,4 @@ class API::StatisticsController < API::ApiController
|
||||
results = Elasticsearch::Model.client.scroll scroll: params[:scroll], scroll_id: params[:scrollId]
|
||||
render json: results
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,3 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Stylesheet
|
||||
# Stylesheets are used to customize the appearance of fab-manager
|
||||
class API::StylesheetsController < API::ApiController
|
||||
caches_page :show # magic happens here
|
||||
|
||||
@ -5,7 +9,7 @@ class API::StylesheetsController < API::ApiController
|
||||
@stylesheet = Stylesheet.find(params[:id])
|
||||
respond_to do |format|
|
||||
format.html # regular ERB template
|
||||
format.css { render :text => @stylesheet.contents, :content_type => 'text/css' }
|
||||
format.css { render text: @stylesheet.contents, content_type: 'text/css' }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Subscription
|
||||
class API::SubscriptionsController < API::ApiController
|
||||
include FablabConfiguration
|
||||
|
||||
@ -64,7 +67,7 @@ class API::SubscriptionsController < API::ApiController
|
||||
params.require(:subscription).permit(:expired_at)
|
||||
end
|
||||
|
||||
# TODO refactor subscriptions logic and move this in model/validator
|
||||
# TODO, refactor subscriptions logic and move this in model/validator
|
||||
def valid_card_token?(token)
|
||||
Stripe::Token.retrieve(token)
|
||||
rescue Stripe::InvalidRequestError => e
|
||||
|
@ -1,3 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Tag
|
||||
# Tags are used to restrict access to Availabilities
|
||||
class API::TagsController < API::ApiController
|
||||
|
||||
before_action :authenticate_user!, except: %i[index show]
|
||||
@ -35,6 +39,7 @@ class API::TagsController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_tag
|
||||
@tag = Tag.find(params[:id])
|
||||
end
|
||||
|
@ -1,3 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Theme
|
||||
# Themes are used in Projects
|
||||
class API::ThemesController < API::ApiController
|
||||
before_action :authenticate_user!, except: %i[index show]
|
||||
before_action :set_theme, only: %i[show update destroy]
|
||||
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Training
|
||||
class API::TrainingsController < API::ApiController
|
||||
include ApplicationHelper
|
||||
|
||||
@ -7,14 +10,12 @@ class API::TrainingsController < API::ApiController
|
||||
def index
|
||||
@requested_attributes = params[:requested_attributes]
|
||||
@trainings = policy_scope(Training)
|
||||
if params[:public_page]
|
||||
@trainings = @trainings.where(public_page: true)
|
||||
end
|
||||
@trainings = @trainings.where(public_page: true) if params[:public_page]
|
||||
|
||||
if attribute_requested?(@requested_attributes, 'availabilities')
|
||||
@trainings = @trainings.includes(availabilities: [slots: [reservation: [user: %i[profile trainings]]]])
|
||||
.order('availabilities.start_at DESC')
|
||||
end
|
||||
return unless attribute_requested?(@requested_attributes, 'availabilities')
|
||||
|
||||
@trainings = @trainings.includes(availabilities: [slots: [reservation: [user: %i[profile trainings]]]])
|
||||
.order('availabilities.start_at DESC')
|
||||
end
|
||||
|
||||
def show
|
||||
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for managing Training prices
|
||||
class API::TrainingsPricingsController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
|
||||
@ -8,9 +11,9 @@ class API::TrainingsPricingsController < API::ApiController
|
||||
def update
|
||||
if current_user.admin?
|
||||
@trainings_pricing = TrainingsPricing.find(params[:id])
|
||||
_trainings_pricing_params = trainings_pricing_params
|
||||
_trainings_pricing_params[:amount] = _trainings_pricing_params[:amount] * 100
|
||||
if @trainings_pricing.update(_trainings_pricing_params)
|
||||
trainings_pricing_parameters = trainings_pricing_params
|
||||
trainings_pricing_parameters[:amount] = trainings_pricing_parameters[:amount] * 100
|
||||
if @trainings_pricing.update(trainings_pricing_parameters)
|
||||
render status: :ok
|
||||
else
|
||||
render status: :unprocessable_entity
|
||||
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for managing front-end translations
|
||||
class API::TranslationsController < API::ApiController
|
||||
before_action :set_locale
|
||||
|
||||
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Users with role :partner
|
||||
class API::UsersController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
|
||||
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller to get the fab-manager version
|
||||
class API::VersionController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
|
||||
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Wallet
|
||||
class API::WalletController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
|
||||
@ -19,9 +22,7 @@ class API::WalletController < API::ApiController
|
||||
service = WalletService.new(user: current_user, wallet: @wallet)
|
||||
transaction = service.credit(credit_params[:amount].to_f)
|
||||
if transaction
|
||||
if credit_params[:avoir]
|
||||
service.create_avoir(transaction, credit_params[:avoir_date], credit_params[:avoir_description])
|
||||
end
|
||||
service.create_avoir(transaction, credit_params[:avoir_date], credit_params[:avoir_description]) if credit_params[:avoir]
|
||||
render :show
|
||||
else
|
||||
head 422
|
||||
|
@ -51,4 +51,9 @@ class ApplicationController < ActionController::Base
|
||||
def current_user
|
||||
super
|
||||
end
|
||||
|
||||
# This is a placeholder for Devise's authenticate_user! method.
|
||||
def authenticate_user!
|
||||
super
|
||||
end
|
||||
end
|
||||
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Coupon is a textual code associated with a discount rate or an amount of discount
|
||||
class Coupon < ActiveRecord::Base
|
||||
has_many :invoices
|
||||
|
||||
@ -6,7 +9,7 @@ class Coupon < ActiveRecord::Base
|
||||
|
||||
validates :name, presence: true
|
||||
validates :code, presence: true
|
||||
validates :code, format: { with: /\A[A-Z0-9\-]+\z/, message: 'only caps letters, numbers, and dashes'}
|
||||
validates :code, format: { with: /\A[A-Z0-9\-]+\z/, message: 'only caps letters, numbers, and dashes' }
|
||||
validates :code, uniqueness: true
|
||||
validates :validity_per_user, presence: true
|
||||
validates :validity_per_user, inclusion: { in: %w[once forever] }
|
||||
@ -52,9 +55,9 @@ class Coupon < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def type
|
||||
if amount_off.nil? and !percent_off.nil?
|
||||
if amount_off.nil? && !percent_off.nil?
|
||||
'percent_off'
|
||||
elsif percent_off.nil? and !amount_off.nil?
|
||||
elsif percent_off.nil? && !amount_off.nil?
|
||||
'amount_off'
|
||||
end
|
||||
end
|
||||
|
@ -27,8 +27,8 @@ class Plan < ActiveRecord::Base
|
||||
|
||||
validates :amount, :group, :base_name, presence: true
|
||||
validates :interval_count, numericality: { only_integer: true, greater_than_or_equal_to: 1 }
|
||||
validates :interval_count, numericality: { less_than: 12 }, if: proc { |plan| plan.interval == 'month' }
|
||||
validates :interval_count, numericality: { less_than: 52 }, if: proc { |plan| plan.interval == 'week' }
|
||||
validates :interval_count, numericality: { less_than: 13 }, if: proc { |plan| plan.interval == 'month' }
|
||||
validates :interval_count, numericality: { less_than: 53 }, if: proc { |plan| plan.interval == 'week' }
|
||||
validates :interval, inclusion: { in: %w[year month week] }
|
||||
validates :base_name, :slug, presence: true
|
||||
|
||||
|
@ -54,6 +54,8 @@ class User < ActiveRecord::Base
|
||||
|
||||
has_many :exports, dependent: :destroy
|
||||
|
||||
has_many :history_values, dependent: :nullify
|
||||
|
||||
# fix for create admin user
|
||||
before_save do
|
||||
email&.downcase!
|
||||
|
@ -2,9 +2,11 @@ class UserPolicy < ApplicationPolicy
|
||||
class Scope < Scope
|
||||
def resolve
|
||||
if user.admin?
|
||||
scope.includes(:group, :training_credits, :machine_credits, :subscriptions => [:plan => [:credits]], :profile => [:user_avatar]).joins(:roles).where("users.is_active = 'true' AND roles.name = 'member'").order('users.created_at desc')
|
||||
scope.includes(:group, :training_credits, :machine_credits, 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'").where(is_allow_contact: true).order('users.created_at desc')
|
||||
scope.includes(profile: [:user_avatar]).joins(:roles).where("users.is_active = 'true' AND roles.name = 'member'")
|
||||
.where(is_allow_contact: true).order('users.created_at desc')
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -25,7 +27,7 @@ class UserPolicy < ApplicationPolicy
|
||||
user.id == record.id
|
||||
end
|
||||
|
||||
%w(list create mapping).each do |action|
|
||||
%w[list create mapping].each do |action|
|
||||
define_method "#{action}?" do
|
||||
user.admin?
|
||||
end
|
||||
|
141
app/services/availabilities/availabilities_service.rb
Normal file
141
app/services/availabilities/availabilities_service.rb
Normal file
@ -0,0 +1,141 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Provides helper methods for Availability resources and properties
|
||||
class Availabilities::AvailabilitiesService
|
||||
|
||||
def initialize(current_user, maximum_visibility = {})
|
||||
@current_user = current_user
|
||||
@maximum_visibility = maximum_visibility
|
||||
@service = Availabilities::StatusService.new(current_user.admin? ? 'admin' : 'user')
|
||||
end
|
||||
|
||||
# list all slots for the given machine, with reservations info, relatives to the given user
|
||||
def machines(machine_id, user)
|
||||
machine = Machine.friendly.find(machine_id)
|
||||
reservations = reservations(machine)
|
||||
availabilities = availabilities(machine, 'machines', user)
|
||||
|
||||
slots = []
|
||||
availabilities.each do |a|
|
||||
((a.end_at - a.start_at) / ApplicationHelper::SLOT_DURATION.minutes).to_i.times do |i|
|
||||
next unless (a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes) > Time.now
|
||||
|
||||
slot = Slot.new(
|
||||
start_at: a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes,
|
||||
end_at: a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes + ApplicationHelper::SLOT_DURATION.minutes,
|
||||
availability_id: a.id,
|
||||
availability: a,
|
||||
machine: machine,
|
||||
title: ''
|
||||
)
|
||||
slot = @service.machine_reserved_status(slot, reservations, @current_user)
|
||||
slots << slot
|
||||
end
|
||||
end
|
||||
slots
|
||||
end
|
||||
|
||||
# list all slots for the given space, with reservations info, relatives to the given user
|
||||
def spaces(space_id, user)
|
||||
space = Space.friendly.find(space_id)
|
||||
reservations = reservations(space)
|
||||
availabilities = availabilities(space, 'space', user)
|
||||
|
||||
slots = []
|
||||
availabilities.each do |a|
|
||||
((a.end_at - a.start_at) / ApplicationHelper::SLOT_DURATION.minutes).to_i.times do |i|
|
||||
next unless (a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes) > Time.now
|
||||
|
||||
slot = Slot.new(
|
||||
start_at: a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes,
|
||||
end_at: a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes + ApplicationHelper::SLOT_DURATION.minutes,
|
||||
availability_id: a.id,
|
||||
availability: a,
|
||||
space: space,
|
||||
title: ''
|
||||
)
|
||||
slot = @service.space_reserved_status(slot, reservations, user)
|
||||
slots << slot
|
||||
end
|
||||
end
|
||||
slots.each do |s|
|
||||
s.title = t('availabilities.not_available') if s.is_complete? && !s.is_reserved
|
||||
end
|
||||
slots
|
||||
end
|
||||
|
||||
# list all slots for the given training, with reservations info, relatives to the given user
|
||||
def trainings(training_id, user)
|
||||
# first, we get the already-made reservations
|
||||
reservations = user.reservations.where("reservable_type = 'Training'")
|
||||
reservations = reservations.where('reservable_id = :id', id: training_id.to_i) if training_id.is_number?
|
||||
reservations = reservations.joins(:slots).where('slots.start_at > ?', Time.now)
|
||||
|
||||
# visible availabilities depends on multiple parameters
|
||||
availabilities = training_availabilities(training_id, user)
|
||||
|
||||
# finally, we merge the availabilities with the reservations
|
||||
availabilities.each do |a|
|
||||
a = @service.training_event_reserved_status(a, reservations, user)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def subscription_year?(user)
|
||||
user.subscription && user.subscription.plan.interval == 'year' && user.subscription.expired_at >= Time.now
|
||||
end
|
||||
|
||||
# member must have validated at least 1 training and must have a valid yearly subscription.
|
||||
def show_extended_slots?(user)
|
||||
user.trainings.size.positive? && subscription_year?(user)
|
||||
end
|
||||
|
||||
def reservations(reservable)
|
||||
Reservation.where('reservable_type = ? and reservable_id = ?', reservable.class.name, reservable.id)
|
||||
.includes(:slots, user: [:profile])
|
||||
.references(:slots, :user)
|
||||
.where('slots.start_at > ?', Time.now)
|
||||
end
|
||||
|
||||
def availabilities(reservable, type, user)
|
||||
if user.admin?
|
||||
reservable.availabilities
|
||||
.includes(:tags)
|
||||
.where('end_at > ? AND available_type = ?', Time.now, type)
|
||||
.where(lock: false)
|
||||
else
|
||||
end_at = @maximum_visibility[:other]
|
||||
end_at = @maximum_visibility[:year] if subscription_year?(user)
|
||||
reservable.availabilities
|
||||
.includes(:tags)
|
||||
.where('end_at > ? AND end_at < ? AND available_type = ?', Time.now, end_at, type)
|
||||
.where('availability_tags.tag_id' => user.tag_ids.concat([nil]))
|
||||
.where(lock: false)
|
||||
end
|
||||
end
|
||||
|
||||
def training_availabilities(training_id, user)
|
||||
availabilities = if training_id.is_number? || (training_id.length.positive? && training_id != 'all')
|
||||
Training.friendly.find(training_id).availabilities
|
||||
else
|
||||
Availability.trainings
|
||||
end
|
||||
|
||||
# who made the request?
|
||||
# 1) an admin (he can see all future availabilities)
|
||||
if @current_user.admin?
|
||||
availabilities.includes(:tags, :slots, trainings: [:machines])
|
||||
.where('availabilities.start_at > ?', Time.now)
|
||||
.where(lock: false)
|
||||
# 2) an user (he cannot see availabilities further than 1 (or 3) months)
|
||||
else
|
||||
end_at = @maximum_visibility[:other]
|
||||
end_at = @maximum_visibility[:year] if show_extended_slots?(user)
|
||||
availabilities.includes(:tags, :slots, :availability_tags, trainings: [:machines])
|
||||
.where('availabilities.start_at > ? AND availabilities.start_at < ?', Time.now, end_at)
|
||||
.where('availability_tags.tag_id' => user.tag_ids.concat([nil]))
|
||||
.where(lock: false)
|
||||
end
|
||||
end
|
||||
end
|
105
app/services/availabilities/public_availabilities_service.rb
Normal file
105
app/services/availabilities/public_availabilities_service.rb
Normal file
@ -0,0 +1,105 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Provides helper methods for public calendar of Availability
|
||||
class Availabilities::PublicAvailabilitiesService
|
||||
def initialize(current_user)
|
||||
@current_user = current_user
|
||||
@service = Availabilities::StatusService.new('')
|
||||
end
|
||||
|
||||
# provides a list of slots and availabilities for the machines, between the given dates
|
||||
def machines(start_date, end_date, reservations, machine_ids)
|
||||
availabilities = Availability.includes(:tags, :machines)
|
||||
.where(available_type: 'machines')
|
||||
.where('start_at >= ? AND end_at <= ?', start_date, end_date)
|
||||
.where(lock: false)
|
||||
slots = []
|
||||
availabilities.each do |a|
|
||||
a.machines.each do |machine|
|
||||
next unless machine_ids&.include?(machine.id.to_s)
|
||||
|
||||
((a.end_at - a.start_at) / ApplicationHelper::SLOT_DURATION.minutes).to_i.times do |i|
|
||||
slot = Slot.new(
|
||||
start_at: a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes,
|
||||
end_at: a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes + ApplicationHelper::SLOT_DURATION.minutes,
|
||||
availability_id: a.id,
|
||||
availability: a,
|
||||
machine: machine,
|
||||
title: machine.name
|
||||
)
|
||||
slot = @service.machine_reserved_status(slot, reservations, @current_user)
|
||||
slots << slot
|
||||
end
|
||||
end
|
||||
end
|
||||
{ availabilities: availabilities, slots: slots }
|
||||
end
|
||||
|
||||
# provides a list of slots and availabilities for the spaces, between the given dates
|
||||
def spaces(start_date, end_date, reservations, available_id)
|
||||
availabilities = Availability.includes(:tags, :spaces).where(available_type: 'space')
|
||||
.where('start_at >= ? AND end_at <= ?', start_date, end_date)
|
||||
.where(lock: false)
|
||||
|
||||
availabilities.where(available_id: available_id) if available_id
|
||||
|
||||
slots = []
|
||||
availabilities.each do |a|
|
||||
space = a.spaces.first
|
||||
((a.end_at - a.start_at) / ApplicationHelper::SLOT_DURATION.minutes).to_i.times do |i|
|
||||
next unless (a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes) > Time.now
|
||||
|
||||
slot = Slot.new(
|
||||
start_at: a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes,
|
||||
end_at: a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes + ApplicationHelper::SLOT_DURATION.minutes,
|
||||
availability_id: a.id,
|
||||
availability: a,
|
||||
space: space,
|
||||
title: space.name
|
||||
)
|
||||
slot = @service.space_reserved_status(slot, reservations, @current_user)
|
||||
slots << slot
|
||||
end
|
||||
end
|
||||
{ availabilities: availabilities, slots: slots }
|
||||
end
|
||||
|
||||
def public_availabilities(start_date, end_date, reservations, ids)
|
||||
if in_same_day(start_date, end_date)
|
||||
# request for 1 single day
|
||||
|
||||
# trainings, events
|
||||
training_event_availabilities = Availability.includes(:tags, :trainings, :slots)
|
||||
.where(available_type: %w[training event])
|
||||
.where('start_at >= ? AND end_at <= ?', start_date, end_date)
|
||||
.where(lock: false)
|
||||
# machines
|
||||
machines_avail = machines(start_date, end_date, reservations, ids[:machines])
|
||||
machine_slots = machines_avail[:slots]
|
||||
# spaces
|
||||
spaces_avail = spaces(start_date, end_date, reservations, ids[:spaces])
|
||||
space_slots = spaces_avail[:slots]
|
||||
|
||||
[].concat(training_event_availabilities).concat(machine_slots).concat(space_slots)
|
||||
else
|
||||
# request for many days (week or month)
|
||||
avails = Availability.includes(:tags, :machines, :trainings, :spaces, :event, :slots)
|
||||
.where('start_at >= ? AND end_at <= ?', start_date, end_date)
|
||||
.where(lock: false)
|
||||
avails.each do |a|
|
||||
if a.available_type == 'training' || a.available_type == 'event'
|
||||
a = @service.training_event_reserved_status(a, reservations, @current_user)
|
||||
elsif a.available_type == 'space'
|
||||
a.is_reserved = @service.reserved_availability?(a, @current_user)
|
||||
end
|
||||
end
|
||||
avails
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def in_same_day(start_date, end_date)
|
||||
(end_date.to_date - start_date.to_date).to_i == 1
|
||||
end
|
||||
end
|
87
app/services/availabilities/status_service.rb
Normal file
87
app/services/availabilities/status_service.rb
Normal file
@ -0,0 +1,87 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Provides helper methods checking reservation status of any availabilities
|
||||
class Availabilities::StatusService
|
||||
def initialize(current_user_role)
|
||||
@current_user_role = current_user_role
|
||||
end
|
||||
|
||||
# check that the provided machine slot is reserved or not and modify it accordingly
|
||||
def machine_reserved_status(slot, reservations, user)
|
||||
show_name = (@current_user_role == 'admin' || Setting.find_by(name: 'display_name_enable').value == 'true')
|
||||
reservations.each do |r|
|
||||
r.slots.each do |s|
|
||||
next unless slot.machine.id == r.reservable_id
|
||||
|
||||
next unless s.start_at == slot.start_at && s.canceled_at.nil?
|
||||
|
||||
slot.id = s.id
|
||||
slot.is_reserved = true
|
||||
slot.title = "#{slot.machine.name} - #{show_name ? r.user.profile.full_name : t('availabilities.not_available')}"
|
||||
slot.can_modify = true if @current_user_role == 'admin'
|
||||
slot.reservations.push r
|
||||
|
||||
next unless r.user == user
|
||||
|
||||
slot.title = "#{slot.machine.name} - #{t('availabilities.i_ve_reserved')}"
|
||||
slot.can_modify = true
|
||||
slot.is_reserved_by_current_user = true
|
||||
end
|
||||
end
|
||||
slot
|
||||
end
|
||||
|
||||
# check that the provided space slot is reserved or not and modify it accordingly
|
||||
def space_reserved_status(slot, reservations, user)
|
||||
reservations.each do |r|
|
||||
r.slots.each do |s|
|
||||
next unless slot.space.id == r.reservable_id
|
||||
|
||||
next unless s.start_at == slot.start_at && s.canceled_at.nil?
|
||||
|
||||
slot.can_modify = true if @current_user_role == 'admin'
|
||||
slot.reservations.push r
|
||||
|
||||
next unless r.user == user
|
||||
|
||||
slot.id = s.id
|
||||
slot.title = t('availabilities.i_ve_reserved')
|
||||
slot.can_modify = true
|
||||
slot.is_reserved = true
|
||||
end
|
||||
end
|
||||
slot
|
||||
end
|
||||
|
||||
# check that the provided availability (training or event) is reserved or not and modify it accordingly
|
||||
def training_event_reserved_status(availability, reservations, user)
|
||||
reservations.each do |r|
|
||||
r.slots.each do |s|
|
||||
next unless (
|
||||
(availability.available_type == 'training' && availability.trainings.first.id == r.reservable_id) ||
|
||||
(availability.available_type == 'event' && availability.event.id == r.reservable_id)
|
||||
) && s.start_at == availability.start_at && s.canceled_at.nil?
|
||||
|
||||
availability.slot_id = s.id
|
||||
if r.user == user
|
||||
availability.is_reserved = true
|
||||
availability.can_modify = true
|
||||
end
|
||||
end
|
||||
end
|
||||
availability
|
||||
end
|
||||
|
||||
# check that the provided ability is reserved by the given user
|
||||
def reserved_availability?(availability, user)
|
||||
if user
|
||||
reserved_slots = []
|
||||
availability.slots.each do |s|
|
||||
reserved_slots << s if s.canceled_at.nil?
|
||||
end
|
||||
reserved_slots.map(&:reservations).flatten.map(&:user_id).include? user.id
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
44
app/services/event_service.rb
Normal file
44
app/services/event_service.rb
Normal file
@ -0,0 +1,44 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Provides helper methods for Events resources and properties
|
||||
class EventService
|
||||
def self.process_params(params)
|
||||
# handle dates & times (whole-day events or not, maybe during many days)
|
||||
range = EventService.date_range({ date: params[:start_date], time: params[:start_time] },
|
||||
{ date: params[:end_date], time: params[:end_time] },
|
||||
params[:all_day] == 'true')
|
||||
params.merge!(availability_attributes: { id: params[:availability_id],
|
||||
start_at: range[:start_at],
|
||||
end_at: range[:end_at],
|
||||
available_type: 'event' })
|
||||
.except!(:start_date, :end_date, :start_time, :end_time, :all_day)
|
||||
# convert main price to centimes
|
||||
params[:amount] = (params[:amount].to_f * 100 if params[:amount].present?)
|
||||
# delete non-complete "other" prices and convert them to centimes
|
||||
unless params[:event_price_categories_attributes].nil?
|
||||
params[:event_price_categories_attributes].delete_if do |price_cat|
|
||||
price_cat[:price_category_id].empty? || price_cat[:amount].empty?
|
||||
end
|
||||
params[:event_price_categories_attributes].each do |price_cat|
|
||||
price_cat[:amount] = price_cat[:amount].to_f * 100
|
||||
end
|
||||
end
|
||||
# return the resulting params object
|
||||
params
|
||||
end
|
||||
|
||||
def self.date_range(starting, ending, all_day)
|
||||
start_date = Time.zone.parse(starting[:date])
|
||||
end_date = Time.zone.parse(ending[:date])
|
||||
start_time = Time.parse(starting[:time]) if starting[:time]
|
||||
end_time = Time.parse(ending[:time]) if ending[:time]
|
||||
if all_day == 'true'
|
||||
start_at = DateTime.new(start_date.year, start_date.month, start_date.day, 0, 0, 0, start_date.zone)
|
||||
end_at = DateTime.new(end_date.year, end_date.month, end_date.day, 23, 59, 59, end_date.zone)
|
||||
else
|
||||
start_at = DateTime.new(start_date.year, start_date.month, start_date.day, start_time.hour, start_time.min, start_time.sec, start_date.zone)
|
||||
end_at = DateTime.new(end_date.year, end_date.month, end_date.day, end_time.hour, end_time.min, end_time.sec, end_date.zone)
|
||||
end
|
||||
{ start_at: start_at, end_at: end_at }
|
||||
end
|
||||
end
|
87
app/services/members/list_service.rb
Normal file
87
app/services/members/list_service.rb
Normal file
@ -0,0 +1,87 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Provides helper methods for listing Users
|
||||
class Members::ListService
|
||||
class << self
|
||||
def list(params)
|
||||
@query = User.includes(:profile, :group, :subscriptions)
|
||||
.joins(:profile,
|
||||
:group,
|
||||
:roles,
|
||||
'LEFT JOIN "subscriptions" ON "subscriptions"."user_id" = "users"."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?
|
||||
@query = @query.where('profiles.first_name ILIKE :search OR ' \
|
||||
'profiles.last_name ILIKE :search OR ' \
|
||||
'profiles.phone ILIKE :search OR ' \
|
||||
'email ILIKE :search OR ' \
|
||||
'groups.name ILIKE :search OR ' \
|
||||
'plans.base_name ILIKE :search', search: "%#{params[:search]}%")
|
||||
end
|
||||
|
||||
@query
|
||||
end
|
||||
|
||||
def search(current_user, query, subscription)
|
||||
members = User.includes(:profile)
|
||||
.joins(:profile,
|
||||
:roles,
|
||||
'LEFT JOIN "subscriptions" ON "subscriptions"."user_id" = "users"."id" AND ' \
|
||||
'"subscriptions"."created_at" = ( ' \
|
||||
'SELECT max("created_at") ' \
|
||||
'FROM "subscriptions" ' \
|
||||
'WHERE "user_id" = "users"."id")')
|
||||
.where("users.is_active = 'true' AND roles.name = 'member'")
|
||||
query.downcase.split(' ').each do |word|
|
||||
members = members.where('lower(f_unaccent(profiles.first_name)) ~ :search OR ' \
|
||||
'lower(f_unaccent(profiles.last_name)) ~ :search',
|
||||
search: word)
|
||||
end
|
||||
|
||||
|
||||
if current_user.member?
|
||||
# non-admin can only retrieve users with "public profiles"
|
||||
members = members.where("users.is_allow_contact = 'true'")
|
||||
elsif subscription == 'true'
|
||||
# only admins have the ability to filter by subscription
|
||||
members = members.where('subscriptions.id IS NOT NULL AND subscriptions.expiration_date >= :now', now: Date.today.to_s)
|
||||
elsif subscription == 'false'
|
||||
members = members.where('subscriptions.id IS NULL OR subscriptions.expiration_date < :now', now: Date.today.to_s)
|
||||
end
|
||||
|
||||
members.to_a
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
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])
|
||||
|
||||
order_key = case order_key
|
||||
when 'last_name'
|
||||
'profiles.last_name'
|
||||
when 'first_name'
|
||||
'profiles.first_name'
|
||||
when 'email'
|
||||
'users.email'
|
||||
when 'phone'
|
||||
'profiles.phone'
|
||||
when 'group'
|
||||
'groups.name'
|
||||
when 'plan'
|
||||
'plans.base_name'
|
||||
else
|
||||
'users.id'
|
||||
end
|
||||
|
||||
"#{order_key} #{direction}"
|
||||
end
|
||||
end
|
||||
end
|
77
app/services/members/members_service.rb
Normal file
77
app/services/members/members_service.rb
Normal file
@ -0,0 +1,77 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Provides helper methods for User actions
|
||||
class Members::MembersService
|
||||
|
||||
attr_accessor :member
|
||||
|
||||
def initialize(member)
|
||||
@member = member
|
||||
end
|
||||
|
||||
def update(params)
|
||||
|
||||
if params[:group_id] && @member.group_id != params[:group_id].to_i && !@member.subscribed_plan.nil?
|
||||
# here a group change is requested but unprocessable, handle the exception
|
||||
@member.errors[:group_id] = I18n.t('members.unable_to_change_the_group_while_a_subscription_is_running')
|
||||
return false
|
||||
end
|
||||
|
||||
not_complete = member.need_completion?
|
||||
up_result = member.update(params)
|
||||
|
||||
notify_user_profile_complete(not_complete) if up_result
|
||||
up_result
|
||||
end
|
||||
|
||||
def create(current_user, params)
|
||||
@member.password = password(params)
|
||||
|
||||
# if the user is created by an admin and the authentication is made through an SSO, generate a migration token
|
||||
@member.generate_auth_migration_token if current_user.admin? && AuthProvider.active.providable_type != DatabaseProvider.name
|
||||
|
||||
if @member.save
|
||||
@member.generate_subscription_invoice
|
||||
@member.send_confirmation_instructions
|
||||
UsersMailer.delay.notify_user_account_created(@member, @member.password)
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def merge_from_sso(user)
|
||||
merge_result = member.merge_from_sso(user)
|
||||
|
||||
notify_admin_user_merged if merge_result
|
||||
merge_result
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def notify_user_profile_complete(previous_state)
|
||||
return unless previous_state && !member.need_completion?
|
||||
|
||||
NotificationCenter.call type: :notify_user_profile_complete,
|
||||
receiver: member,
|
||||
attached_object: member
|
||||
NotificationCenter.call type: :notify_admin_profile_complete,
|
||||
receiver: User.admins,
|
||||
attached_object: member
|
||||
end
|
||||
|
||||
def notify_admin_user_merged
|
||||
NotificationCenter.call type: :notify_admin_user_merged,
|
||||
receiver: User.admins,
|
||||
attached_object: member
|
||||
end
|
||||
|
||||
def password(params)
|
||||
if !params[:password] && !params[:password_confirmation]
|
||||
Devise.friendly_token.first(8)
|
||||
else
|
||||
params[:password]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
@ -1,45 +0,0 @@
|
||||
|
||||
class MembersService
|
||||
|
||||
attr_accessor :member
|
||||
|
||||
def initialize(member)
|
||||
@member = member
|
||||
end
|
||||
|
||||
def update(params)
|
||||
not_complete = self.member.need_completion?
|
||||
up_result = self.member.update(params)
|
||||
if up_result
|
||||
notify_user_profile_complete(not_complete)
|
||||
end
|
||||
up_result
|
||||
end
|
||||
|
||||
def merge_from_sso(user)
|
||||
merge_result = self.member.merge_from_sso(user)
|
||||
if merge_result
|
||||
notify_admin_user_merged
|
||||
end
|
||||
merge_result
|
||||
end
|
||||
|
||||
private
|
||||
def notify_user_profile_complete(previous_state)
|
||||
if previous_state and not self.member.need_completion?
|
||||
NotificationCenter.call type: :notify_user_profile_complete,
|
||||
receiver: self.member,
|
||||
attached_object: self.member
|
||||
NotificationCenter.call type: :notify_admin_profile_complete,
|
||||
receiver: User.admins,
|
||||
attached_object: self.member
|
||||
end
|
||||
end
|
||||
|
||||
def notify_admin_user_merged
|
||||
NotificationCenter.call type: :notify_admin_user_merged,
|
||||
receiver: User.admins,
|
||||
attached_object: self.member
|
||||
end
|
||||
|
||||
end
|
26
app/services/plans_service.rb
Normal file
26
app/services/plans_service.rb
Normal file
@ -0,0 +1,26 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Provides methods for Plan & PartnerPlan actions
|
||||
class PlansService
|
||||
class << self
|
||||
def create(type, partner, params)
|
||||
if params[:group_id] == 'all'
|
||||
plans = type.constantize.create_for_all_groups(params)
|
||||
return false unless plans
|
||||
|
||||
plans.each { |plan| partner.add_role :partner, plan } unless partner.nil?
|
||||
{ plan_ids: plans.map(&:id) }
|
||||
else
|
||||
plan = type.constantize.new(params)
|
||||
if plan.save
|
||||
partner&.add_role :partner, plan
|
||||
plan
|
||||
else
|
||||
{ errors: @plan.errors }
|
||||
end
|
||||
end
|
||||
rescue Stripe::InvalidRequestError => e
|
||||
{ errors: e.message }
|
||||
end
|
||||
end
|
||||
end
|
@ -1,7 +1,5 @@
|
||||
max_members = @query.except(:offset, :limit, :order).count
|
||||
|
||||
json.array!(@members) do |member|
|
||||
json.maxMembers max_members
|
||||
json.maxMembers @max_members
|
||||
json.id member.id
|
||||
json.email member.email if current_user
|
||||
json.profile do
|
||||
@ -13,7 +11,9 @@ json.array!(@members) do |member|
|
||||
json.group do
|
||||
json.name member.group.name
|
||||
end
|
||||
json.subscribed_plan do
|
||||
json.partial! 'api/shared/plan', plan: member.subscribed_plan
|
||||
end if member.subscribed_plan
|
||||
end
|
||||
if member.subscribed_plan
|
||||
json.subscribed_plan do
|
||||
json.partial! 'api/shared/plan', plan: member.subscribed_plan
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -3,9 +3,11 @@ json.setting do
|
||||
if @show_history
|
||||
json.history @setting.history_values do |value|
|
||||
json.extract! value, :value, :created_at
|
||||
json.user do
|
||||
json.id value.user_id
|
||||
json.name "#{value.user.first_name} #{value.user.last_name}"
|
||||
unless value.user_id.nil?
|
||||
json.user do
|
||||
json.id value.user_id
|
||||
json.name "#{value.user.first_name} #{value.user.last_name}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -367,6 +367,7 @@ en:
|
||||
VAT_history: "VAT rates history"
|
||||
changed_at: "Changed at"
|
||||
changed_by: "By"
|
||||
deleted_user: "Deleted user"
|
||||
refund_invoice_successfully_created: "Refund invoice successfully created."
|
||||
create_a_refund_on_this_invoice: "Create a refund on this invoice"
|
||||
creation_date_for_the_refund: "Creation date for the refund"
|
||||
|
@ -367,6 +367,7 @@ es:
|
||||
VAT_history: "Historial de ratios de IVA"
|
||||
changed_at: "Cambiado en"
|
||||
changed_by: "Por"
|
||||
deleted_user: "Usario eliminado"
|
||||
refund_invoice_successfully_created: "Factura de reembolso creada correctamente."
|
||||
create_a_refund_on_this_invoice: "Crear un reembolso en esta factura"
|
||||
creation_date_for_the_refund: "Fecha de creación del reembolso"
|
||||
|
@ -367,6 +367,7 @@ fr:
|
||||
VAT_history: "Historique des taux de TVA"
|
||||
changed_at: "Changé le"
|
||||
changed_by: "Par"
|
||||
deleted_user: "Utilisateur supprimé"
|
||||
refund_invoice_successfully_created: "La facture d'avoir a bien été créée."
|
||||
create_a_refund_on_this_invoice: "Générer un avoir sur cette facture"
|
||||
creation_date_for_the_refund: "Date d'émission de l'avoir"
|
||||
|
@ -367,6 +367,7 @@ pt:
|
||||
VAT_history: "VAT rates history" #translation_missing
|
||||
changed_at: "Changed at" #translation_missing
|
||||
changed_by: "By" #translation_missing
|
||||
deleted_user: "Deleted user" #translation_missing
|
||||
refund_invoice_successfully_created: "Restituição de fatura criada com sucesso."
|
||||
create_a_refund_on_this_invoice: "Criar restituição de fatura"
|
||||
creation_date_for_the_refund: "Criação de data de restituição"
|
||||
|
@ -211,6 +211,7 @@ en:
|
||||
plan_form:
|
||||
general_information: "General information"
|
||||
name: "Name"
|
||||
name_is_required: "Name is required"
|
||||
name_length_must_be_less_than_24_characters: "Name length must be less than 24 characters."
|
||||
type: "Type"
|
||||
type_is_required: "Type is required."
|
||||
|
@ -211,6 +211,7 @@ es:
|
||||
plan_form:
|
||||
general_information: "Información general"
|
||||
name: "Nombre"
|
||||
name_is_required: "Se requiere un nombre."
|
||||
name_length_must_be_less_than_24_characters: "el nombre debe contener menos de 24 caracteres."
|
||||
type: "Tipo"
|
||||
type_is_required: "Se requiere un tipo."
|
||||
|
@ -211,6 +211,7 @@ fr:
|
||||
plan_form:
|
||||
general_information: "Informations générales"
|
||||
name: "Nom"
|
||||
name_is_required: "Le nom est requis"
|
||||
name_length_must_be_less_than_24_characters: "Le nom doit faire moins de 24 caractères."
|
||||
type: "Type"
|
||||
type_is_required: "Le type est requis."
|
||||
|
@ -211,6 +211,7 @@ pt:
|
||||
plan_form:
|
||||
general_information: "Informação geral"
|
||||
name: "Nome"
|
||||
name_is_required: "Nome é obrigatório."
|
||||
name_length_must_be_less_than_24_characters: "O nome deve conter no máximo 24 caracteres."
|
||||
type: "Tipo"
|
||||
type_is_required: "Tipo é obrigatório."
|
||||
|
190
db/schema.rb
190
db/schema.rb
@ -15,8 +15,8 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
enable_extension "pg_trgm"
|
||||
enable_extension "unaccent"
|
||||
enable_extension "pg_trgm"
|
||||
|
||||
create_table "abuses", force: :cascade do |t|
|
||||
t.integer "signaled_id"
|
||||
@ -31,24 +31,15 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
|
||||
add_index "abuses", ["signaled_type", "signaled_id"], name: "index_abuses_on_signaled_type_and_signaled_id", using: :btree
|
||||
|
||||
create_table "accounting_periods", force: :cascade do |t|
|
||||
t.date "start_at"
|
||||
t.date "end_at"
|
||||
t.datetime "closed_at"
|
||||
t.integer "closed_by"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
create_table "addresses", force: :cascade do |t|
|
||||
t.string "address", limit: 255
|
||||
t.string "street_number", limit: 255
|
||||
t.string "route", limit: 255
|
||||
t.string "locality", limit: 255
|
||||
t.string "country", limit: 255
|
||||
t.string "postal_code", limit: 255
|
||||
t.string "address"
|
||||
t.string "street_number"
|
||||
t.string "route"
|
||||
t.string "locality"
|
||||
t.string "country"
|
||||
t.string "postal_code"
|
||||
t.integer "placeable_id"
|
||||
t.string "placeable_type", limit: 255
|
||||
t.string "placeable_type"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
@ -64,9 +55,9 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
|
||||
create_table "assets", force: :cascade do |t|
|
||||
t.integer "viewable_id"
|
||||
t.string "viewable_type", limit: 255
|
||||
t.string "attachment", limit: 255
|
||||
t.string "type", limit: 255
|
||||
t.string "viewable_type"
|
||||
t.string "attachment"
|
||||
t.string "type"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
@ -83,12 +74,12 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
create_table "availabilities", force: :cascade do |t|
|
||||
t.datetime "start_at"
|
||||
t.datetime "end_at"
|
||||
t.string "available_type", limit: 255
|
||||
t.string "available_type"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.integer "nb_total_places"
|
||||
t.boolean "destroying", default: false
|
||||
t.boolean "lock", default: false
|
||||
t.boolean "destroying", default: false
|
||||
t.boolean "lock", default: false
|
||||
end
|
||||
|
||||
create_table "availability_tags", force: :cascade do |t|
|
||||
@ -102,7 +93,7 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
add_index "availability_tags", ["tag_id"], name: "index_availability_tags_on_tag_id", using: :btree
|
||||
|
||||
create_table "categories", force: :cascade do |t|
|
||||
t.string "name", limit: 255
|
||||
t.string "name"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.string "slug"
|
||||
@ -111,7 +102,7 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
add_index "categories", ["slug"], name: "index_categories_on_slug", unique: true, using: :btree
|
||||
|
||||
create_table "components", force: :cascade do |t|
|
||||
t.string "name", limit: 255, null: false
|
||||
t.string "name", null: false
|
||||
end
|
||||
|
||||
create_table "coupons", force: :cascade do |t|
|
||||
@ -129,7 +120,7 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
|
||||
create_table "credits", force: :cascade do |t|
|
||||
t.integer "creditable_id"
|
||||
t.string "creditable_type", limit: 255
|
||||
t.string "creditable_type"
|
||||
t.integer "plan_id"
|
||||
t.integer "hours"
|
||||
t.datetime "created_at"
|
||||
@ -170,7 +161,7 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
add_index "event_themes", ["slug"], name: "index_event_themes_on_slug", unique: true, using: :btree
|
||||
|
||||
create_table "events", force: :cascade do |t|
|
||||
t.string "title", limit: 255
|
||||
t.string "title"
|
||||
t.text "description"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
@ -208,10 +199,10 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
add_index "exports", ["user_id"], name: "index_exports_on_user_id", using: :btree
|
||||
|
||||
create_table "friendly_id_slugs", force: :cascade do |t|
|
||||
t.string "slug", limit: 255, null: false
|
||||
t.integer "sluggable_id", null: false
|
||||
t.string "slug", null: false
|
||||
t.integer "sluggable_id", null: false
|
||||
t.string "sluggable_type", limit: 50
|
||||
t.string "scope", limit: 255
|
||||
t.string "scope"
|
||||
t.datetime "created_at"
|
||||
end
|
||||
|
||||
@ -221,10 +212,10 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
add_index "friendly_id_slugs", ["sluggable_type"], name: "index_friendly_id_slugs_on_sluggable_type", using: :btree
|
||||
|
||||
create_table "groups", force: :cascade do |t|
|
||||
t.string "name", limit: 255
|
||||
t.string "name"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.string "slug", limit: 255
|
||||
t.string "slug"
|
||||
t.boolean "disabled"
|
||||
end
|
||||
|
||||
@ -243,7 +234,7 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
|
||||
create_table "invoice_items", force: :cascade do |t|
|
||||
t.integer "invoice_id"
|
||||
t.string "stp_invoice_item_id", limit: 255
|
||||
t.string "stp_invoice_item_id"
|
||||
t.integer "amount"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
@ -256,17 +247,17 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
|
||||
create_table "invoices", force: :cascade do |t|
|
||||
t.integer "invoiced_id"
|
||||
t.string "invoiced_type", limit: 255
|
||||
t.string "stp_invoice_id", limit: 255
|
||||
t.string "invoiced_type"
|
||||
t.string "stp_invoice_id"
|
||||
t.integer "total"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.integer "user_id"
|
||||
t.string "reference", limit: 255
|
||||
t.string "avoir_mode", limit: 255
|
||||
t.string "reference"
|
||||
t.string "avoir_mode"
|
||||
t.datetime "avoir_date"
|
||||
t.integer "invoice_id"
|
||||
t.string "type", limit: 255
|
||||
t.string "type"
|
||||
t.boolean "subscription_to_expire"
|
||||
t.text "description"
|
||||
t.integer "wallet_amount"
|
||||
@ -280,17 +271,17 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
add_index "invoices", ["wallet_transaction_id"], name: "index_invoices_on_wallet_transaction_id", using: :btree
|
||||
|
||||
create_table "licences", force: :cascade do |t|
|
||||
t.string "name", limit: 255, null: false
|
||||
t.string "name", null: false
|
||||
t.text "description"
|
||||
end
|
||||
|
||||
create_table "machines", force: :cascade do |t|
|
||||
t.string "name", limit: 255, null: false
|
||||
t.string "name", null: false
|
||||
t.text "description"
|
||||
t.text "spec"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.string "slug", limit: 255
|
||||
t.string "slug"
|
||||
t.boolean "disabled"
|
||||
end
|
||||
|
||||
@ -307,14 +298,14 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
create_table "notifications", force: :cascade do |t|
|
||||
t.integer "receiver_id"
|
||||
t.integer "attached_object_id"
|
||||
t.string "attached_object_type", limit: 255
|
||||
t.string "attached_object_type"
|
||||
t.integer "notification_type_id"
|
||||
t.boolean "is_read", default: false
|
||||
t.boolean "is_read", default: false
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.string "receiver_type"
|
||||
t.boolean "is_send", default: false
|
||||
t.jsonb "meta_data", default: {}
|
||||
t.boolean "is_send", default: false
|
||||
t.jsonb "meta_data", default: {}
|
||||
end
|
||||
|
||||
add_index "notifications", ["notification_type_id"], name: "index_notifications_on_notification_type_id", using: :btree
|
||||
@ -383,20 +374,20 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
add_index "organizations", ["profile_id"], name: "index_organizations_on_profile_id", using: :btree
|
||||
|
||||
create_table "plans", force: :cascade do |t|
|
||||
t.string "name", limit: 255
|
||||
t.string "name"
|
||||
t.integer "amount"
|
||||
t.string "interval", limit: 255
|
||||
t.string "interval"
|
||||
t.integer "group_id"
|
||||
t.string "stp_plan_id", limit: 255
|
||||
t.string "stp_plan_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.integer "training_credit_nb", default: 0
|
||||
t.boolean "is_rolling", default: true
|
||||
t.integer "training_credit_nb", default: 0
|
||||
t.boolean "is_rolling", default: true
|
||||
t.text "description"
|
||||
t.string "type"
|
||||
t.string "base_name"
|
||||
t.integer "ui_weight", default: 0
|
||||
t.integer "interval_count", default: 1
|
||||
t.integer "ui_weight", default: 0
|
||||
t.integer "interval_count", default: 1
|
||||
t.string "slug"
|
||||
t.boolean "disabled"
|
||||
end
|
||||
@ -426,11 +417,11 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
|
||||
create_table "profiles", force: :cascade do |t|
|
||||
t.integer "user_id"
|
||||
t.string "first_name", limit: 255
|
||||
t.string "last_name", limit: 255
|
||||
t.string "first_name"
|
||||
t.string "last_name"
|
||||
t.boolean "gender"
|
||||
t.date "birthday"
|
||||
t.string "phone", limit: 255
|
||||
t.string "phone"
|
||||
t.text "interest"
|
||||
t.text "software_mastered"
|
||||
t.datetime "created_at"
|
||||
@ -460,7 +451,7 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
t.integer "project_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.string "title", limit: 255
|
||||
t.string "title"
|
||||
t.integer "step_nb"
|
||||
end
|
||||
|
||||
@ -471,27 +462,27 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
t.integer "user_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.boolean "is_valid", default: false
|
||||
t.string "valid_token", limit: 255
|
||||
t.boolean "is_valid", default: false
|
||||
t.string "valid_token"
|
||||
end
|
||||
|
||||
add_index "project_users", ["project_id"], name: "index_project_users_on_project_id", using: :btree
|
||||
add_index "project_users", ["user_id"], name: "index_project_users_on_user_id", using: :btree
|
||||
|
||||
create_table "projects", force: :cascade do |t|
|
||||
t.string "name", limit: 255
|
||||
t.string "name"
|
||||
t.text "description"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.integer "author_id"
|
||||
t.text "tags"
|
||||
t.integer "licence_id"
|
||||
t.string "state", limit: 255
|
||||
t.string "slug", limit: 255
|
||||
t.string "state"
|
||||
t.string "slug"
|
||||
t.datetime "published_at"
|
||||
end
|
||||
|
||||
add_index "projects", ["slug"], name: "index_projects_on_slug", using: :btree
|
||||
add_index "projects", ["slug"], name: "index_projects_on_slug", unique: true, using: :btree
|
||||
|
||||
create_table "projects_components", force: :cascade do |t|
|
||||
t.integer "project_id"
|
||||
@ -531,19 +522,19 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
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"
|
||||
t.string "stp_invoice_id"
|
||||
t.integer "nb_reserve_places"
|
||||
end
|
||||
|
||||
add_index "reservations", ["reservable_id", "reservable_type"], name: "index_reservations_on_reservable_id_and_reservable_type", using: :btree
|
||||
add_index "reservations", ["reservable_type", "reservable_id"], name: "index_reservations_on_reservable_type_and_reservable_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
|
||||
t.string "name"
|
||||
t.integer "resource_id"
|
||||
t.string "resource_type", limit: 255
|
||||
t.string "resource_type"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
@ -617,18 +608,18 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
|
||||
create_table "statistic_fields", force: :cascade do |t|
|
||||
t.integer "statistic_index_id"
|
||||
t.string "key", limit: 255
|
||||
t.string "label", limit: 255
|
||||
t.string "key"
|
||||
t.string "label"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.string "data_type", limit: 255
|
||||
t.string "data_type"
|
||||
end
|
||||
|
||||
add_index "statistic_fields", ["statistic_index_id"], name: "index_statistic_fields_on_statistic_index_id", using: :btree
|
||||
|
||||
create_table "statistic_graphs", force: :cascade do |t|
|
||||
t.integer "statistic_index_id"
|
||||
t.string "chart_type", limit: 255
|
||||
t.string "chart_type"
|
||||
t.integer "limit"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
@ -637,17 +628,17 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
add_index "statistic_graphs", ["statistic_index_id"], name: "index_statistic_graphs_on_statistic_index_id", using: :btree
|
||||
|
||||
create_table "statistic_indices", force: :cascade do |t|
|
||||
t.string "es_type_key", limit: 255
|
||||
t.string "label", limit: 255
|
||||
t.string "es_type_key"
|
||||
t.string "label"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.boolean "table", default: true
|
||||
t.boolean "ca", default: true
|
||||
t.boolean "table", default: true
|
||||
t.boolean "ca", default: true
|
||||
end
|
||||
|
||||
create_table "statistic_sub_types", force: :cascade do |t|
|
||||
t.string "key", limit: 255
|
||||
t.string "label", limit: 255
|
||||
t.string "key"
|
||||
t.string "label"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
@ -664,8 +655,8 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
|
||||
create_table "statistic_types", force: :cascade do |t|
|
||||
t.integer "statistic_index_id"
|
||||
t.string "key", limit: 255
|
||||
t.string "label", limit: 255
|
||||
t.string "key"
|
||||
t.string "label"
|
||||
t.boolean "graph"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
@ -683,7 +674,7 @@ ActiveRecord::Schema.define(version: 20190110150532) 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"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "expiration_date"
|
||||
@ -702,7 +693,7 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
add_index "tags", ["name"], name: "index_tags_on_name", unique: true, using: :btree
|
||||
|
||||
create_table "themes", force: :cascade do |t|
|
||||
t.string "name", limit: 255, null: false
|
||||
t.string "name", null: false
|
||||
end
|
||||
|
||||
create_table "tickets", force: :cascade do |t|
|
||||
@ -717,13 +708,13 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
add_index "tickets", ["reservation_id"], name: "index_tickets_on_reservation_id", using: :btree
|
||||
|
||||
create_table "trainings", force: :cascade do |t|
|
||||
t.string "name", limit: 255
|
||||
t.string "name"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.integer "nb_total_places"
|
||||
t.string "slug", limit: 255
|
||||
t.string "slug"
|
||||
t.text "description"
|
||||
t.boolean "public_page", default: true
|
||||
t.boolean "public_page", default: true
|
||||
t.boolean "disabled"
|
||||
end
|
||||
|
||||
@ -779,31 +770,31 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
add_index "user_trainings", ["user_id"], name: "index_user_trainings_on_user_id", using: :btree
|
||||
|
||||
create_table "users", force: :cascade do |t|
|
||||
t.string "email", limit: 255, default: "", null: false
|
||||
t.string "encrypted_password", limit: 255, default: "", null: false
|
||||
t.string "reset_password_token", limit: 255
|
||||
t.string "email", default: "", null: false
|
||||
t.string "encrypted_password", default: "", null: false
|
||||
t.string "reset_password_token"
|
||||
t.datetime "reset_password_sent_at"
|
||||
t.datetime "remember_created_at"
|
||||
t.integer "sign_in_count", default: 0, null: false
|
||||
t.integer "sign_in_count", default: 0, null: false
|
||||
t.datetime "current_sign_in_at"
|
||||
t.datetime "last_sign_in_at"
|
||||
t.string "current_sign_in_ip", limit: 255
|
||||
t.string "last_sign_in_ip", limit: 255
|
||||
t.string "confirmation_token", limit: 255
|
||||
t.string "current_sign_in_ip"
|
||||
t.string "last_sign_in_ip"
|
||||
t.string "confirmation_token"
|
||||
t.datetime "confirmed_at"
|
||||
t.datetime "confirmation_sent_at"
|
||||
t.string "unconfirmed_email", limit: 255
|
||||
t.integer "failed_attempts", default: 0, null: false
|
||||
t.string "unlock_token", limit: 255
|
||||
t.string "unconfirmed_email"
|
||||
t.integer "failed_attempts", default: 0, null: false
|
||||
t.string "unlock_token"
|
||||
t.datetime "locked_at"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.boolean "is_allow_contact", default: true
|
||||
t.boolean "is_allow_contact", default: true
|
||||
t.integer "group_id"
|
||||
t.string "stp_customer_id", limit: 255
|
||||
t.string "username", limit: 255
|
||||
t.string "slug", limit: 255
|
||||
t.boolean "is_active", default: true
|
||||
t.string "stp_customer_id"
|
||||
t.string "username"
|
||||
t.string "slug"
|
||||
t.boolean "is_active", default: true
|
||||
t.string "provider"
|
||||
t.string "uid"
|
||||
t.string "auth_token"
|
||||
@ -864,7 +855,6 @@ ActiveRecord::Schema.define(version: 20190110150532) do
|
||||
|
||||
add_index "wallets", ["user_id"], name: "index_wallets_on_user_id", using: :btree
|
||||
|
||||
add_foreign_key "accounting_periods", "users", column: "closed_by"
|
||||
add_foreign_key "availability_tags", "availabilities"
|
||||
add_foreign_key "availability_tags", "tags"
|
||||
add_foreign_key "event_price_categories", "events"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "fab-manager",
|
||||
"version": "2.8.1",
|
||||
"version": "2.8.2-dev",
|
||||
"description": "FabManager is the FabLab management solution. It is web-based, open-source and totally free.",
|
||||
"keywords": [
|
||||
"fablab",
|
||||
|
@ -1,3 +1,4 @@
|
||||
# frozen_string_literal: true
|
||||
module Events
|
||||
class AsAdminTest < ActionDispatch::IntegrationTest
|
||||
|
||||
@ -11,16 +12,16 @@ module Events
|
||||
# First, we create a new event
|
||||
post '/api/events',
|
||||
{
|
||||
event: {
|
||||
title: 'OpenLab discovery day',
|
||||
description: 'A day to discover the Fablab and try its machines and possibilities.',
|
||||
start_date: 1.week.from_now.utc,
|
||||
start_time: 1.week.from_now.utc.change({hour: 16}),
|
||||
end_date: 1.week.from_now.utc,
|
||||
end_time: 1.week.from_now.utc.change({hour: 20}),
|
||||
category_id: Category.first.id,
|
||||
amount: 0
|
||||
}
|
||||
event: {
|
||||
title: 'OpenLab discovery day',
|
||||
description: 'A day to discover the Fablab and try its machines and possibilities.',
|
||||
start_date: 1.week.from_now.utc,
|
||||
start_time: 1.week.from_now.utc.change(hour: 16),
|
||||
end_date: 1.week.from_now.utc,
|
||||
end_time: 1.week.from_now.utc.change(hour: 20),
|
||||
category_id: Category.first.id,
|
||||
amount: 0
|
||||
}
|
||||
}.to_json,
|
||||
default_headers
|
||||
|
||||
@ -38,18 +39,16 @@ module Events
|
||||
|
||||
# Then, modify the event to set a nb of places
|
||||
put "/api/events/#{e.id}",
|
||||
{
|
||||
event: {
|
||||
title: 'OpenLab discovery day',
|
||||
description: 'A day to discover the Fablab and try its machines and possibilities.',
|
||||
start_date: 1.week.from_now.utc,
|
||||
start_time: 1.week.from_now.utc.change({hour: 16}),
|
||||
end_date: 1.week.from_now.utc,
|
||||
end_time: 1.week.from_now.utc.change({hour: 20}),
|
||||
category_id: Category.first.id,
|
||||
amount: 0,
|
||||
nb_total_places: 10
|
||||
}
|
||||
event: {
|
||||
title: 'OpenLab discovery day',
|
||||
description: 'A day to discover the Fablab and try its machines and possibilities.',
|
||||
start_date: 1.week.from_now.utc,
|
||||
start_time: 1.week.from_now.utc.change(hour: 16),
|
||||
end_date: 1.week.from_now.utc,
|
||||
end_time: 1.week.from_now.utc.change(hour: 20),
|
||||
category_id: Category.first.id,
|
||||
amount: 0,
|
||||
nb_total_places: 10
|
||||
}
|
||||
|
||||
# Check response format & status
|
||||
@ -63,23 +62,23 @@ module Events
|
||||
|
||||
# Now, let's make a reservation on this event
|
||||
post '/api/reservations',
|
||||
{
|
||||
reservation: {
|
||||
user_id: User.find_by(username: 'pdurand').id,
|
||||
reservable_id: e.id,
|
||||
reservable_type: 'Event',
|
||||
nb_reserve_places: 2,
|
||||
slots_attributes: [
|
||||
{
|
||||
start_at: e.availability.start_at,
|
||||
end_at: e.availability.end_at,
|
||||
availability_id: e.availability.id,
|
||||
offered: false
|
||||
}
|
||||
]
|
||||
}
|
||||
}.to_json,
|
||||
default_headers
|
||||
{
|
||||
reservation: {
|
||||
user_id: User.find_by(username: 'pdurand').id,
|
||||
reservable_id: e.id,
|
||||
reservable_type: 'Event',
|
||||
nb_reserve_places: 2,
|
||||
slots_attributes: [
|
||||
{
|
||||
start_at: e.availability.start_at,
|
||||
end_at: e.availability.end_at,
|
||||
availability_id: e.availability.id,
|
||||
offered: false
|
||||
}
|
||||
]
|
||||
}
|
||||
}.to_json,
|
||||
default_headers
|
||||
|
||||
# Check response format & status
|
||||
assert_equal 201, response.status, response.body
|
||||
@ -91,18 +90,16 @@ module Events
|
||||
|
||||
# Finally, modify the event to add some places
|
||||
put "/api/events/#{e.id}",
|
||||
{
|
||||
event: {
|
||||
title: 'OpenLab discovery day',
|
||||
description: 'A day to discover the Fablab and try its machines and possibilities.',
|
||||
start_date: 1.week.from_now.utc,
|
||||
start_time: 1.week.from_now.utc.change({hour: 16}),
|
||||
end_date: 1.week.from_now.utc,
|
||||
end_time: 1.week.from_now.utc.change({hour: 20}),
|
||||
category_id: Category.first.id,
|
||||
amount: 0,
|
||||
nb_total_places: 20
|
||||
}
|
||||
event: {
|
||||
title: 'OpenLab discovery day',
|
||||
description: 'A day to discover the Fablab and try its machines and possibilities.',
|
||||
start_date: 1.week.from_now.utc,
|
||||
start_time: 1.week.from_now.utc.change(hour: 16),
|
||||
end_date: 1.week.from_now.utc,
|
||||
end_time: 1.week.from_now.utc.change(hour: 20),
|
||||
category_id: Category.first.id,
|
||||
amount: 0,
|
||||
nb_total_places: 20
|
||||
}
|
||||
|
||||
# Check response format & status
|
||||
@ -122,23 +119,23 @@ module Events
|
||||
# First, we create a new event
|
||||
post '/api/events',
|
||||
{
|
||||
event: {
|
||||
title: 'Electronics initiation',
|
||||
description: 'A workshop about electronics and the abilities to create robots.',
|
||||
start_date: 1.week.from_now.utc + 2.days,
|
||||
start_time: 1.week.from_now.utc.change({hour: 18}) + 2.days,
|
||||
end_date: 1.week.from_now.utc + 2.days,
|
||||
end_time: 1.week.from_now.utc.change({hour: 22}) + 2.days,
|
||||
category_id: Category.last.id,
|
||||
amount: 20,
|
||||
nb_total_places: 10,
|
||||
event_price_categories_attributes: [
|
||||
{
|
||||
price_category_id: price_category.id.to_s,
|
||||
amount: 16.to_s
|
||||
}
|
||||
]
|
||||
}
|
||||
event: {
|
||||
title: 'Electronics initiation',
|
||||
description: 'A workshop about electronics and the abilities to create robots.',
|
||||
start_date: 1.week.from_now.utc + 2.days,
|
||||
start_time: 1.week.from_now.utc.change(hour: 18) + 2.days,
|
||||
end_date: 1.week.from_now.utc + 2.days,
|
||||
end_time: 1.week.from_now.utc.change(hour: 22) + 2.days,
|
||||
category_id: Category.last.id,
|
||||
amount: 20,
|
||||
nb_total_places: 10,
|
||||
event_price_categories_attributes: [
|
||||
{
|
||||
price_category_id: price_category.id.to_s,
|
||||
amount: 16.to_s
|
||||
}
|
||||
]
|
||||
}
|
||||
}.to_json,
|
||||
default_headers
|
||||
|
||||
@ -159,26 +156,26 @@ module Events
|
||||
# Now, let's make a reservation on this event
|
||||
post '/api/reservations',
|
||||
{
|
||||
reservation: {
|
||||
user_id: User.find_by(username: 'lseguin').id,
|
||||
reservable_id: e.id,
|
||||
reservable_type: 'Event',
|
||||
nb_reserve_places: 4,
|
||||
slots_attributes: [
|
||||
{
|
||||
start_at: e.availability.start_at,
|
||||
end_at: e.availability.end_at,
|
||||
availability_id: e.availability.id,
|
||||
offered: false
|
||||
}
|
||||
],
|
||||
tickets_attributes: [
|
||||
{
|
||||
event_price_category_id: e.event_price_categories.first.id,
|
||||
booked: 4
|
||||
}
|
||||
]
|
||||
}
|
||||
reservation: {
|
||||
user_id: User.find_by(username: 'lseguin').id,
|
||||
reservable_id: e.id,
|
||||
reservable_type: 'Event',
|
||||
nb_reserve_places: 4,
|
||||
slots_attributes: [
|
||||
{
|
||||
start_at: e.availability.start_at,
|
||||
end_at: e.availability.end_at,
|
||||
availability_id: e.availability.id,
|
||||
offered: false
|
||||
}
|
||||
],
|
||||
tickets_attributes: [
|
||||
{
|
||||
event_price_category_id: e.event_price_categories.first.id,
|
||||
booked: 4
|
||||
}
|
||||
]
|
||||
}
|
||||
}.to_json,
|
||||
default_headers
|
||||
|
||||
@ -203,4 +200,4 @@ module Events
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -84,4 +84,18 @@ class MembersTest < ActionDispatch::IntegrationTest
|
||||
assert_equal 2, res[:group_id], "user's group does not match"
|
||||
assert_equal instagram, res[:profile][:instagram], "user's social network not updated"
|
||||
end
|
||||
|
||||
test 'admin search for autocompletion of a member s name' do
|
||||
get '/api/members/search/kevin?subscription=true'
|
||||
|
||||
# Check response format & status
|
||||
assert_equal 200, response.status, response.body
|
||||
assert_equal Mime::JSON, response.content_type
|
||||
|
||||
# Check search result
|
||||
res = json_response(response.body)
|
||||
assert_equal 1, res.length
|
||||
|
||||
assert_match /Kevin/, res[0][:name]
|
||||
end
|
||||
end
|
||||
|
@ -1,4 +1,4 @@
|
||||
module Events
|
||||
module Prices
|
||||
class AsAdminTest < ActionDispatch::IntegrationTest
|
||||
|
||||
setup do
|
||||
@ -13,19 +13,19 @@ module Events
|
||||
|
||||
post '/api/prices/compute',
|
||||
{
|
||||
reservation: {
|
||||
user_id: user.id,
|
||||
reservable_id: printer_training.id,
|
||||
reservable_type: printer_training.class.name,
|
||||
slots_attributes: [
|
||||
{
|
||||
availability_id: availability.id,
|
||||
end_at: availability.end_at,
|
||||
offered: false,
|
||||
start_at: availability.start_at
|
||||
}
|
||||
]
|
||||
}
|
||||
reservation: {
|
||||
user_id: user.id,
|
||||
reservable_id: printer_training.id,
|
||||
reservable_type: printer_training.class.name,
|
||||
slots_attributes: [
|
||||
{
|
||||
availability_id: availability.id,
|
||||
end_at: availability.end_at,
|
||||
offered: false,
|
||||
start_at: availability.start_at
|
||||
}
|
||||
]
|
||||
}
|
||||
}.to_json,
|
||||
default_headers
|
||||
|
||||
@ -35,7 +35,9 @@ module Events
|
||||
|
||||
# Check the price was computed correctly
|
||||
price = json_response(response.body)
|
||||
assert_equal (printer_training.trainings_pricings.where(group_id: user.group_id).first.amount / 100.0), price[:price], 'Computed price did not match training price'
|
||||
assert_equal (printer_training.trainings_pricings.where(group_id: user.group_id).first.amount / 100.0),
|
||||
price[:price],
|
||||
'Computed price did not match training price'
|
||||
end
|
||||
|
||||
|
||||
@ -47,26 +49,26 @@ module Events
|
||||
|
||||
post '/api/prices/compute',
|
||||
{
|
||||
reservation: {
|
||||
user_id: user.id,
|
||||
reservable_id: laser.id,
|
||||
reservable_type: laser.class.name,
|
||||
plan_id: plan.id,
|
||||
slots_attributes: [
|
||||
{
|
||||
availability_id: availability.id,
|
||||
end_at: (availability.start_at + 1.hour).strftime('%Y-%m-%d %H:%M:%S.%9N Z'),
|
||||
offered: true,
|
||||
start_at: availability.start_at.strftime('%Y-%m-%d %H:%M:%S.%9N Z')
|
||||
},
|
||||
{
|
||||
availability_id: availability.id,
|
||||
end_at: (availability.start_at + 2.hour).strftime('%Y-%m-%d %H:%M:%S.%9N Z'),
|
||||
offered: false,
|
||||
start_at: (availability.start_at + 1.hour).strftime('%Y-%m-%d %H:%M:%S.%9N Z')
|
||||
}
|
||||
]
|
||||
}
|
||||
reservation: {
|
||||
user_id: user.id,
|
||||
reservable_id: laser.id,
|
||||
reservable_type: laser.class.name,
|
||||
plan_id: plan.id,
|
||||
slots_attributes: [
|
||||
{
|
||||
availability_id: availability.id,
|
||||
end_at: (availability.start_at + 1.hour).strftime('%Y-%m-%d %H:%M:%S.%9N Z'),
|
||||
offered: true,
|
||||
start_at: availability.start_at.strftime('%Y-%m-%d %H:%M:%S.%9N Z')
|
||||
},
|
||||
{
|
||||
availability_id: availability.id,
|
||||
end_at: (availability.start_at + 2.hour).strftime('%Y-%m-%d %H:%M:%S.%9N Z'),
|
||||
offered: false,
|
||||
start_at: (availability.start_at + 1.hour).strftime('%Y-%m-%d %H:%M:%S.%9N Z')
|
||||
}
|
||||
]
|
||||
}
|
||||
}.to_json,
|
||||
default_headers
|
||||
|
||||
@ -76,7 +78,9 @@ module Events
|
||||
|
||||
# Check the event was created correctly
|
||||
price = json_response(response.body)
|
||||
assert_equal ((laser.prices.where(group_id: user.group_id, plan_id: plan.id).first.amount + plan.amount) / 100.0), price[:price], 'Computed price did not match machine + subscription price'
|
||||
assert_equal ((laser.prices.where(group_id: user.group_id, plan_id: plan.id).first.amount + plan.amount) / 100.0),
|
||||
price[:price],
|
||||
'Computed price did not match machine + subscription price'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user