Skip to content

Commit 60a99e4

Browse files
committed
Merge branch 'dev' for release 6.0.14
2 parents 5e6e4b8 + 48d76fa commit 60a99e4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+287
-107
lines changed

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
# Changelog Fab-manager
22

3+
## next deploy
4+
5+
## v6.0.14 2023 September 6
6+
7+
- Fix a bug: for project categories, if there is no category : do not show categories panel in show view, do not show categories input field in edit view
8+
- Fix a bug: unable to update status to paid for latest payment schedule item
9+
- Fix a bug: unable to generate statistic
10+
- Fix a bug: unable to update user profile by admin
11+
- Feature: add a filter in members list (admin) to show only "not validated" members
12+
- Concerning statistics:
13+
- removes age and type column from all statistics tabs (only in web, not in xlsx export file)
14+
- index:
15+
- renames user column header for projects tab and projects xlsx export
16+
- adds group name of user for every tab except projects tab
17+
- adds status and project users names for projects tab
18+
- [TODO DEPLOY] `rails db:seed`
19+
- [TODO DEPLOY] `rails fablab:es:build_stats`
20+
- [TODO DEPLOY] `rails fablab:maintenance:regenerate_statistics[2014,1]`
21+
322
## v6.0.13 2023 August 28
423

524
- Fix a bug: unable to cancel a payment schedule

app/controllers/api/notification_types_controller.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ class API::NotificationTypesController < API::APIController
66

77
def index
88
@notification_types = if params[:is_configurable] == 'true'
9-
NotificationType.where(is_configurable: true)
9+
role = 'admin' if current_user.admin?
10+
role ||= 'manager' if current_user.manager?
11+
NotificationType.where(is_configurable: true).for_role(role)
1012
else
1113
NotificationType.all
1214
end

app/frontend/src/javascript/components/editorial-block/editorial-block.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import React from 'react';
22
import { IApplication } from '../../models/application';
33
import { Loader } from '../base/loader';
44
import { react2angular } from 'react2angular';
5-
import { FabButton } from '../base/fab-button';
65
import { SettingValue } from '../../models/setting';
76

87
declare const Application: IApplication;
@@ -17,15 +16,12 @@ interface EditorialBlockProps {
1716
* Display a editorial text block with an optional cta button
1817
*/
1918
export const EditorialBlock: React.FC<EditorialBlockProps> = ({ text, cta, url }) => {
20-
/** Link to url from props */
21-
const linkTo = (): void => {
22-
window.location.href = url as string;
23-
};
24-
2519
return (
2620
<div className={`editorial-block ${(cta as string)?.length > 25 ? 'long-cta' : ''}`}>
2721
<div dangerouslySetInnerHTML={{ __html: text as string }}></div>
28-
{cta && <FabButton className='is-main' onClick={linkTo}>{cta}</FabButton>}
22+
{cta &&
23+
<a href={url as string} target="_blank" rel="noopener noreferrer" className='fab-button is-main cta'>{cta}</a>
24+
}
2925
</div>
3026
);
3127
};

app/frontend/src/javascript/components/notifications/notifications-center.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export const NotificationsCenter: React.FC<NotificationsCenterProps> = ({ onErro
3030

3131
return (
3232
<>
33-
{role === 'admin' && <FabTabs defaultTab='notifications-list' tabs={[
33+
{(role === 'admin' || role === 'manager') && <FabTabs defaultTab='notifications-list' tabs={[
3434
{
3535
id: 'notifications_settings',
3636
title: t('app.logged.notifications_center.notifications_settings'),
@@ -42,7 +42,7 @@ export const NotificationsCenter: React.FC<NotificationsCenterProps> = ({ onErro
4242
content: <NotificationsList onError={onError}/>
4343
}
4444
]} />}
45-
{role !== 'admin' && <NotificationsList onError={onError}/>}
45+
{role === 'member' && <NotificationsList onError={onError}/>}
4646
</>
4747
);
4848
};

app/frontend/src/javascript/components/user/user-profile-form.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ export const UserProfileForm: React.FC<UserProfileFormProps> = ({ action, size,
136136
}
137137

138138
return handleSubmit((data: User) => {
139+
['events_reservations', 'space_reservations', 'training_reservations', 'machine_reservations', 'all_projects', 'invoices', 'subscribed_plan', 'subscription'].forEach(key => delete data[key]);
139140
MemberAPI[action](data)
140141
.then(res => {
141142
reset(res);

app/frontend/src/javascript/controllers/admin/members.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ Application.Controllers.controller('AdminMembersController', ['$scope', '$sce',
163163
// is user validation required
164164
$scope.enableUserValidationRequired = (settingsPromise.user_validation_required === 'true');
165165

166+
if ($scope.enableUserValidationRequired) { $scope.member.memberFilters.push('not_validated'); }
167+
166168
// should we display the username in the list?
167169
$scope.displayUsername = (settingsPromise.show_username_in_admin_list === 'true');
168170

app/frontend/src/stylesheets/modules/base/editorial-block.scss

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,20 @@
77
border: 1px solid var(--gray-soft-dark);
88
border-radius: var(--border-radius);
99
@include editor;
10-
button { white-space: normal; }
10+
.cta {
11+
white-space: normal;
12+
text-decoration: none;
13+
}
1114

1215
@media (min-width: 540px) {
1316
flex-direction: row;
1417
justify-content: space-between;
1518
align-items: flex-end;
16-
button { white-space: nowrap; }
19+
.cta { white-space: nowrap; }
1720
&.long-cta {
1821
flex-direction: column;
1922
align-items: flex-start;
20-
button { margin-left: auto; }
23+
.cta { margin-left: auto; }
2124
}
2225
}
2326
@media (min-width: 1200px) {

app/frontend/templates/admin/statistics/index.html

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -256,12 +256,11 @@ <h1 translate>{{ 'app.admin.statistics.statistics' }}</h1>
256256
<tr>
257257
<th ng-if="['booking', 'hour'].includes(type.active.key)" translate>{{ 'app.admin.statistics.reservation_date' }}</th>
258258
<th ng-if="!['booking', 'hour'].includes(type.active.key)" translate>{{ 'app.admin.statistics.date' }}</th>
259-
<th translate>{{ 'app.admin.statistics.user' }}</th>
259+
<th ng-if="['project'].includes(type.active.key)" translate>{{ 'app.admin.statistics.project_author' }}</th>
260+
<th ng-if="!['project'].includes(type.active.key)" translate>{{ 'app.admin.statistics.user' }}</th>
260261
<th ng-if="reservationContextFeatureEnabled && reservationContextIsApplicable(selectedIndex.es_type_key)">
261262
{{ 'app.admin.statistics.reservation_context' | translate }}
262263
</th>
263-
<th translate>{{ 'app.admin.statistics.age' }}</th>
264-
<th translate>{{ 'app.admin.statistics.type' }}</th>
265264
<th ng-if="!type.active.simple">{{type.active.label}}</th>
266265
<th ng-repeat="field in selectedIndex.additional_fields">{{field.label}}</th>
267266
<th ng-if="selectedIndex.ca">{{ 'app.admin.statistics.revenue' | translate }}
@@ -285,11 +284,6 @@ <h1 translate>{{ 'app.admin.statistics.statistics' }}</h1>
285284
<td ng-if="reservationContextFeatureEnabled && reservationContextIsApplicable(selectedIndex.es_type_key)">
286285
{{ formatReservationContext(datum._source.reservationContextId) }}
287286
</td>
288-
<td>
289-
<span ng-if="datum._source.age">{{datum._source.age}} {{ 'app.admin.statistics.years_old' | translate }}</span>
290-
<span ng-if="!datum._source.age" translate>{{ 'app.admin.statistics.unknown' }}</span>
291-
</td>
292-
<td>{{formatSubtype(datum._source.subType)}}</td>
293287
<td ng-if="!type.active.simple">{{datum._source.stat}}</td>
294288
<td ng-repeat="field in selectedIndex.additional_fields">
295289
<ng-switch on="field.data_type">

app/frontend/templates/projects/_form.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ <h3 translate>{{ 'app.shared.project.tags' }}</h3>
279279
</div>
280280
</div>
281281

282-
<div class="widget panel b-a m m-t-lg">
282+
<div class="widget panel b-a m m-t-lg" ng-if="projectCategories.length">
283283
<div class="panel-heading b-b small">
284284
<h3 translate>{{ projectCategoriesWording }}</h3>
285285
</div>

app/frontend/templates/projects/show.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ <h3 translate>{{ 'app.shared.project.tags' }}</h3>
174174
</div>
175175
</section>
176176

177-
<section class="widget panel b-a m" ng-if="project.project_categories">
177+
<section class="widget panel b-a m" ng-if="project.project_categories.length">
178178
<div class="panel-heading b-b">
179179
<h3 translate>{{ projectCategoriesWording }}</h3>
180180
</div>

app/models/concerns/stat_concern.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ module StatConcern
1313
attribute :gender, String
1414
attribute :age, Integer
1515
attribute :group, String
16+
attribute :groupName, String
1617

1718
# has include Elasticsearch::Persistence::Model
1819
index_name 'stats'

app/models/notification_type.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,14 @@ class NotificationType < ApplicationRecord
1818
validates :category, presence: true, inclusion: { in: %w[subscriptions user projects deprecated exports agenda trainings accountings
1919
app_management wallet payments users_accounts supporting_documents shop] }
2020
validates :is_configurable, inclusion: { in: [true, false] }
21+
22+
validate :validate_roles
23+
24+
scope :for_role, ->(role) { where("roles @> ?", "{#{role}}") }
25+
26+
private
27+
28+
def validate_roles
29+
errors.add(:roles, :invalid) if roles.any? { |r| !r.in?(%w(admin manager)) }
30+
end
2131
end

app/models/stats/project.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,6 @@ class Stats::Project
1212
attribute :components, Array
1313
attribute :machines, Array
1414
attribute :users, Integer
15+
attribute :status, String
16+
attribute :projectUserNames, Array
1517
end

app/models/user.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ class User < ApplicationRecord
8989
scope :with_subscription, -> { joins(statistic_profile: [:subscriptions]) }
9090
scope :not_confirmed, -> { where(confirmed_at: nil) }
9191
scope :inactive_for_3_years, -> { where('users.last_sign_in_at < ?', 3.years.ago) }
92+
scope :not_validated, -> { where(validated_at: nil) }
9293

9394
def to_json(*)
9495
ApplicationController.new.view_context.render(

app/policies/notification_preference_policy.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
# Check the access policies for API::NotificationPreferencesController
44
class NotificationPreferencePolicy < ApplicationPolicy
55
def update?
6-
user.admin?
6+
user.admin? || user.manager?
77
end
88

99
def bulk_update?
10-
user.admin?
10+
user.admin? || user.manager?
1111
end
1212
end

app/services/members/list_service.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def list(params)
3535
'plans.base_name ILIKE :search', search: "%#{params[:search]}%")
3636
end
3737

38-
filter = params[:filter].presence_in(%w[inactive_for_3_years not_confirmed]) || nil
38+
filter = params[:filter].presence_in(%w[inactive_for_3_years not_confirmed not_validated]) || nil
3939
@query = @query.send(filter) if filter
4040

4141
@query

app/services/statistics/builders/members_builder_service.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,17 @@ def build(options = default_options)
1111
Stats::Account.create({ date: format_date(m[:date]),
1212
type: 'member',
1313
subType: 'created',
14-
stat: 1 }.merge(user_info_stat(m)))
14+
stat: 1,
15+
groupName: m[:groupName] }.merge(user_info_stat(m)))
1516
end
1617

1718
# member ca list
1819
Statistics::FetcherService.members_ca_list(options).each do |m|
1920
Stats::User.create({ date: format_date(m[:date]),
2021
type: 'revenue',
2122
subType: m[:group],
22-
stat: m[:ca] }.merge(user_info_stat(m)))
23+
stat: m[:ca],
24+
groupName: m[:groupName] }.merge(user_info_stat(m)))
2325
end
2426
end
2527
end

app/services/statistics/builders/reservations_builder_service.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ def build(options = default_options)
1919
name: r["#{category}_name".to_sym],
2020
reservationId: r[:reservation_id],
2121
reservationContextId: r[:reservation_context_id],
22-
coupon: r[:coupon]
22+
coupon: r[:coupon],
23+
groupName: r[:groupName],
2324
}.merge(user_info_stat(r)))
2425
stat[:stat] = (type == 'booking' ? 1 : r[:nb_hours])
2526
stat["#{category}Id".to_sym] = r["#{category}_id".to_sym]

app/services/statistics/builders/store_orders_builder_service.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def build(options = default_options)
2323
orderId: o[:order_id],
2424
state: o[:order_state],
2525
coupon: o[:coupon],
26+
groupName: o[:groupName],
2627
stat: 1 }.merge(user_info_stat(o)))
2728
end
2829
end

app/services/statistics/concerns/projects_concern.rb

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ def get_project_users(project)
3131
sum
3232
end
3333

34+
def get_project_user_names(project)
35+
project.project_users.map do |project_user|
36+
{ id: project_user.user.id, name: project_user.user.profile.full_name }
37+
end
38+
end
39+
3440
def project_info(project)
3541
{
3642
project_id: project.id,
@@ -41,7 +47,9 @@ def project_info(project)
4147
project_themes: get_project_themes(project),
4248
project_components: get_projects_components(project),
4349
project_machines: get_projects_machines(project),
44-
project_users: get_project_users(project)
50+
project_users: get_project_users(project),
51+
project_status: project.status&.name,
52+
project_user_names: get_project_user_names(project),
4553
}
4654
end
4755

@@ -53,7 +61,9 @@ def project_info_stat(project)
5361
themes: project[:project_themes],
5462
components: project[:project_components],
5563
machines: project[:project_machines],
56-
users: project[:project_users]
64+
users: project[:project_users],
65+
status: project[:project_status],
66+
projectUserNames: project[:project_user_names],
5767
}
5868
end
5969
end

0 commit comments

Comments
 (0)