"DI\\autowire",
"DI\\Container",
"DI\\ContainerBuilder",
+ "DI\\Attribute\\Inject",
"// Not detected, do not know why.",
"Psr\\Http\\Server\\RequestHandlerInterface"
Changes
-------
+1.0.3 -> 1.0.4
+
+- Cannot access tabs definition on some resolutions
+- HTML Email preview shows source
+- Fix scrolling in emailing preview's modal
+- Few fixes on dependency injection usage
+- Number of show member automatically set to "all"
+- Groups modification not visually added on member form
+- Fix redirection when dynamic file does not exists
+- Menu horizontal scroll when name is too long
+- Should not select a member as its own parent
+- Add preferences footer in replacements
+
1.0.2 -> 1.0.3
-* Logo in mail signature is not shown
-* Missing HTML editor for dynamic fields information field
-* Update and maintainance pages are no longer working
-* Do not throw events on mass edition
-* Make cache version dependent
-* Check preferences website is valid
-* Link to asso website from logo
-* Rework UI messages
+- Logo in mail signature is not shown
+- Missing HTML editor for dynamic fields information field
+- Update and maintainance pages are no longer working
+- Do not throw events on mass edition
+- Make cache version dependent
+- Check preferences website is valid
+- Link to asso website from logo
+- Rework UI messages
1.0.1 -> 1.0.2
namespace Galette\Controllers;
+use Galette\Core\Db;
+use Galette\Core\History;
+use Galette\Core\I18n;
+use Galette\Core\L10n;
+use Galette\Core\Login;
+use Galette\Core\Logo;
+use Galette\Core\Plugins;
+use Galette\Core\Preferences;
+use Galette\Core\PrintLogo;
+use Galette\Entity\FieldsConfig;
+use Galette\Entity\ListsConfig;
use Psr\Container\ContainerInterface;
+use RKA\Session;
+use Slim\Flash\Messages;
use Slim\Psr7\Request;
use Slim\Psr7\Response;
use Slim\Routing\RouteContext;
use Slim\Routing\RouteParser;
+use DI\Attribute\Inject;
+use Slim\Views\Twig;
/**
* Galette abstract controller
{
private $container;
/**
- * @var \Galette\Core\Db
+ * @var Db
*/
#[Inject]
- protected $zdb;
+ protected Db $zdb;
/**
- * @var \Galette\Core\Login
+ * @var Login
*/
#[Inject]
- protected $login;
+ protected Login $login;
/**
- * @var \Galette\Core\Preferences
+ * @var Preferences
*/
#[Inject]
- protected $preferences;
+ protected Preferences $preferences;
/**
- * @var \Slim\Views\Twig
+ * @var Twig
*/
- protected $view;
+ #[Inject]
+ protected Twig $view;
/**
- * @var \Galette\Core\Logo
+ * @var Logo
*/
#[Inject]
- protected $logo;
+ protected Logo $logo;
/**
- * @var \Galette\Core\PrintLogo
+ * @var PrintLogo
*/
#[Inject]
- protected $print_logo;
+ protected PrintLogo $print_logo;
/**
- * @var \Galette\Core\Plugins
+ * @var Plugins
*/
#[Inject]
- protected $plugins;
+ protected Plugins $plugins;
/**
- * @var \Slim\Routing\RouteParser
+ * @var RouteParser
*/
#[Inject]
- protected $routeparser;
+ protected RouteParser $routeparser;
/**
- * @var \Galette\Core\History
+ * @var History
*/
#[Inject]
- protected $history;
+ protected History $history;
/**
- * @var \Galette\Core\I18n
+ * @var I18n
*/
#[Inject]
- protected $i18n;
+ protected I18n $i18n;
/**
- * @var \Galette\Core\L10n
+ * @var L10n
*/
#[Inject]
- protected $l10n;
+ protected L10n $l10n;
/**
- * Session
+ * @var Session
*/
#[Inject("session")]
- protected $session;
+ protected Session $session;
/**
- * @var \Slim\Flash\Messages
+ * @var Messages
*/
#[Inject]
- protected $flash;
+ protected Messages $flash;
/**
- * @var \Galette\Entity\FieldsConfig
+ * @var FieldsConfig
*/
#[Inject]
- protected $fields_config;
+ protected FieldsConfig $fields_config;
/**
- * @var \Galette\Entity\ListsConfig
+ * @var ListsConfig
*/
#[Inject]
- protected $lists_config;
+ protected ListsConfig $lists_config;
/**
* @var array
*/
#[Inject("members_fields")]
- protected $members_fields;
+ protected array $members_fields;
/**
* @var array
*/
#[Inject("members_form_fields")]
- protected $members_form_fields;
+ protected array $members_form_fields;
/**
* @var array
*/
#[Inject("members_fields_cats")]
- protected $members_fields_cats;
+ protected array $members_fields_cats;
/**
* Constructor
public function __construct(ContainerInterface $container)
{
$this->container = $container;
- //set various services we need
- $this->zdb = $container->get('zdb');
- $this->login = $container->get('login');
- $this->preferences = $container->get('preferences');
- $this->view = $container->get(\Slim\Views\Twig::class);
- $this->logo = $container->get('logo');
- $this->print_logo = $container->get('print_logo');
- $this->routeparser = $container->get(RouteParser::class);
- $this->history = $container->get('history');
- $this->i18n = $container->get('i18n');
- $this->l10n = $container->get('l10n');
- $this->session = $container->get('session');
- $this->flash = $container->get('flash');
- $this->fields_config = $container->get('fields_config');
- $this->lists_config = $container->get('lists_config');
- $this->members_fields = $container->get('members_fields');
- $this->members_form_fields = $container->get('members_form_fields');
- $this->members_fields_cats = $container->get('members_fields_cats');
- $this->plugins = $container->get('plugins');
}
/**
_T("The file does not exists or cannot be read :(")
);
+ $route_name = 'member';
+ if ($form_name == 'contrib') {
+ $route_name = 'contribution';
+ } elseif ($form_name == 'trans') {
+ $route_name = 'transaction';
+ }
+
return $response
->withHeader(
'Location',
- $this->routeparser->urlFor('member', ['id' => $id])
+ $this->routeparser->urlFor($route_name, ['id' => (string)$id])
);
}
}
$navigate = array();
if (isset($this->session->{$this->getFilterName()})) {
- $filters = $this->session->{$this->getFilterName()};
+ $filters = clone $this->session->{$this->getFilterName()};
} else {
$filters = new MembersList();
}
$this->setRecipients($_recipients);
$this->subject = $rs->mailing_subject;
$this->message = $rs->mailing_body;
+ $this->html = $this->message != strip_tags($this->message) ? true : false;
if ($rs->mailing_sender_name !== null || $rs->mailing_sender_address !== null) {
$this->setSender(
$rs->mailing_sender_name,
}
/**
- * Get image file contents
+ * Get image file content
*
* @return mixed
*/
namespace Galette\Core;
+use DI\Attribute\Inject;
+
/**
* Plugin controllers trait
*
}
break;
case 'parent_id':
- $this->$prop = ($value instanceof Adherent) ? (int)$value->id : (int)$value;
- $this->loadParent();
+ $pid = ($value instanceof Adherent) ? (int)$value->id : (int)$value;
+ if ($pid === $this->id) {
+ $this->errors[] = _T("A member cannot be its own parent!");
+ $this->$prop = null;
+ } else {
+ $this->$prop = $pid;
+ $this->loadParent();
+ }
break;
}
}
use NumberFormatter;
use PHPMailer\PHPMailer\PHPMailer;
use Slim\Routing\RouteParser;
+use DI\Attribute\Inject;
/**
* Replacements feature
'login_uri' => [
'title' => _T("Galette's login URI"),
'pattern' => '/{LOGIN_URI}/'
+ ],
+ 'asso_footer' => [
+ 'title' => trim(trim(_T("Footer text:"), ':')),
+ 'pattern' => '/{ASSO_FOOTER}/'
]
];
}
//TRANS: see https://www.php.net/manual/datetime.format.php
'date_now' => date(_T('Y-m-d')),
'login_uri' => $this->preferences->getURL() . $this->routeparser->urlFor('login'),
+ 'asso_footer' => $this->preferences->pref_footer
)
);
break;
default:
Analog::log(
- '[MembersList] Unable to set proprety `' . $name . '`',
+ '[MembersList] Unable to set property `' . $name . '`',
Analog::WARNING
);
break;
<div class="ui large labels">
{% for group in groups %}
{% if member.isGroupMember(group.getName()) or member.isGroupManager(group.getName()) %}
- <span class="ui label">
{% if member.isGroupMember(group.getName()) %}
+ <span class="ui label member">
<i class="ui tag icon tooltip" title="{{ _T("Member of group") }}" aria-hidden="true"></i>
{% endif %}
{% if member.isGroupManager(group.getName()) %}
+ <span class="ui label manager">
<i class="ui shield icon tooltip" title="{{ _T("Group manager") }}" aria-hidden="true"></i>
{% endif %}
{{ group.getName() }}
</div>
</div>
</nav>
- {% include "elements/modes.html.twig" %}
+ <div class="ui basic compact fitted segment">
+ {% include "elements/modes.html.twig" %}
+ </div>
{% else %}
{% set component_classes = "ui vertical centered tiny icon fluid menu" %}
<nav id="logoutmenu" class="{{ component_classes }}" aria-label="{{ _T('User menu') }}">
<div class="ui top attached accordion-styled header">
{{ _T("Mail body") }}
</div>
- <div class="ui bottom attached accordion-styled segment">
+ <div class="ui bottom attached accordion-styled{% if mode == 'ajax' %} scrolling{% endif %} segment">
{% if mailing.html %}
- {{ mailing.message }}
+ {{ mailing.message|raw }}
{% else %}
<pre>{{ mailing.wrapped_message|escape }}</pre>
{% endif %}
{% include "elements/js/modal.js.twig" with {
modal_title_twig: _T("Mailing preview")|e("js"),
modal_content: "res",
- modal_content_class: "scrolling",
+ modal_class: "scrolling",
modal_deny_only: true,
modal_cancel_text: _T("Close")|e("js")
} %}
//remove actual groups
var _form = (_managed) ? 'managed' : 'user';
$('#' + _form + 'groups_form').empty();
- var _groups = new Array();
- var _groups_str = '<br/><strong>';
- if ( _managed ) {
- _groups_str += '{{ _T("Manager for:")|e('js') }}';
+ var _existing_labels = $('#groups_field .labels').children().length;
+ var _new_labels = 0;
+ if ($('#groups_field .labels').length === 0) {
+ var _labels_container = '<div class="ui large labels"></div>';
+ $('#btngroups').before(_labels_container);
} else {
- _groups_str += '{{ _T("Member of:")|e('js') }}';
+ if (_managed) {
+ $('#groups_field .labels').find('.label.manager').remove();
+ } else {
+ $('#groups_field .labels').find('.label.member').remove();
+ }
}
- _groups_str += '</strong> ';
+ var _groups = new Array();
+ var _groups_str = '';
$('li[id^="group_"]').each(function(){
//get group values
_gid + '|' + _gname + '|' +
'" name="' + _iname + '[]">'
);
- if ( _groups.length > 1 ) {
- _groups_str += ', ';
+ if (_managed) {
+ _groups_str += '<span class="ui orange basic label manager">';
+ _groups_str += '<i class="ui shield icon tooltip" title="' + '{{ _T("Group manager")|e('js') }}' + '" aria-hidden="true"></i>';
+ } else {
+ _groups_str += '<span class="ui orange basic label member">';
+ _groups_str += '<i class="ui tag icon tooltip" title="' + '{{ _T("Member of group")|e('js') }}' + '" aria-hidden="true"></i>';
}
_groups_str += _gname;
+ _groups_str += '</span>';
+ _new_labels += 1;
});
- $('#' + _form + 'groups').html(_groups_str);
+ $('#groups_field .labels').append(_groups_str);
+ var _modified = '<div class="ui yellow tiny message with-transition">{{ _T("Items in this list have been modified. Don't forget to save your changes.")|e('js') }}</div>';
+ if (_existing_labels != _new_labels) {
+ $('#groups_field').find('.message').remove();
+ $('#groups_field').append(_modified);
+ }
+ $('.message.with-transition').transition('flash');
$('.groups-selection').modal('hide');
});
{% block content %}
<form action="{{ url_for('store-preferences') }}" method="post" enctype="multipart/form-data" class="ui form">
- <div class="ui stackable pointing inverted menu tabbed">
+ <div class="ui stackable pointing inverted wrapping centered fluid menu tabbed">
<a href="{{ url_for('preferences') }}?tab=general" class="item{{ tab == 'general' ? ' active' }}" data-tab="general">{{ _T("General") }}</a>
<a href="{{ url_for('preferences') }}?tab=social" class="item{{ tab == 'social' ? ' active' }}" data-tab="social">{{ _T("Social networks") }}</a>
<a href="{{ url_for('preferences') }}?tab=parameters" class="item{{ tab == 'parameters' ? ' active' }}" data-tab="parameters">{{ _T("Parameters") }}</a>
- galette/includes/
dynamicConstantNames:
- GALETTE_NIGHTLY
+ universalObjectCratesClasses:
+ - RKA\Session
ignoreErrors:
- '/Instantiated class XHProfRuns_Default not found/'
- - '/Attribute class .*\\Inject does not exist./'
- '/Cannot access property .* on .*ArrayObject.*/'
- '/Access to an undefined property ArrayObject.*/'
$response = new \Slim\Psr7\Response();
$controller = new \Galette\Controllers\PdfController($this->container);
+ $this->container->injectOn($controller);
$test_response = $controller->storeModels($request, $response);
$this->assertSame(
$response = new \Slim\Psr7\Response();
$controller = new \Galette\Controllers\PdfController($this->container);
+ $this->container->injectOn($controller);
//test with non-logged-in user
$test_response = $controller->membersCards($request, $response, $this->adh->id);
$response = new \Slim\Psr7\Response();
$controller = new \Galette\Controllers\PdfController($this->container);
+ $this->container->injectOn($controller);
//test logged-in as superadmin
$this->logSuperAdmin();
$response = new \Slim\Psr7\Response();
$controller = new \Galette\Controllers\PdfController($this->container);
+ $this->container->injectOn($controller);
//test with non-logged-in user
$test_response = $controller->membersLabels($request, $response, $this->adh->id);
$response = new \Slim\Psr7\Response();
$controller = new \Galette\Controllers\PdfController($this->container);
+ $this->container->injectOn($controller);
//test logged-in as superadmin
$this->logSuperAdmin();
$response = new \Slim\Psr7\Response();
$controller = new \Galette\Controllers\PdfController($this->container);
+ $this->container->injectOn($controller);
//test with non-logged-in user
$test_response = $controller->adhesionForm($request, $response, $this->adh->id);
$response = new \Slim\Psr7\Response();
$controller = new \Galette\Controllers\PdfController($this->container);
+ $this->container->injectOn($controller);
//test no selection
$test_response = null;
$response = new \Slim\Psr7\Response();
$controller = new \Galette\Controllers\PdfController($this->container);
+ $this->container->injectOn($controller);
//test not logged
$test_response = $controller->contribution($request, $response, $this->contrib->id);
{
$legend = $this->preferences->getLegend();
$this->assertCount(2, $legend);
- $this->assertCount(8, $legend['main']['patterns']);
+ $this->assertCount(9, $legend['main']['patterns']);
$this->assertCount(10, $legend['socials']['patterns']);
$this->assertSame(
[
'asso_website' => '/{ASSO_WEBSITE}/',
'asso_logo' => '/{ASSO_LOGO}/',
'date_now' => '/{DATE_NOW}/',
- 'login_uri' => '/{LOGIN_URI}/'
+ 'login_uri' => '/{LOGIN_URI}/',
+ 'asso_footer' => '/{ASSO_FOOTER}/',
];
$this->assertSame($main_expected, $model->getPatterns());
$this->assertArrayHasKey('member', $legend);
$this->assertArrayHasKey('contribution', $legend);
- $this->assertCount(8, $legend['main']['patterns']);
+ $this->assertCount(9, $legend['main']['patterns']);
$this->assertCount(28, $legend['member']['patterns']);
$this->assertTrue(isset($legend['member']['patterns']['label_dynfield_' . $adf->getId() . '_adh']));
$this->assertCount(14, $legend['contribution']['patterns']);
//get csv model file to add data in
$controller = new \Galette\Controllers\CsvController($this->container);
+ $this->container->injectOn($controller);
$rfactory = new \Slim\Psr7\Factory\RequestFactory();
$request = $rfactory->createRequest('GET', 'http://localhost/models/csv');
color: @hoveredTextColor;
}
+/* -----------------------------------------------
+ Wrapping pointing inverted tabbed menus
+------------------------------------------------ */
+.ui.wrapping.menu.tabbed .item:last-child,
+.ui.wrapping.menu.tabbed .item:last-of-type {
+ border-right-color: transparent !important;
+}
+.ui.wrapping.menu.tabbed .item::before {
+ right: 0;
+ left: auto;
+}
+
/*------------------
Pagination
-------------------*/
max-width: 100%;
}
+aside .ui.small.compact.fluid.menu .ui.item {
+ max-width: 14.688rem;
+}
+
.loggedin .content {
.ui.horizontal.segments.header {
flex-direction: row-reverse;