19 Commits

Author SHA1 Message Date
ab1148872e Fixed organisation member action button aria labels 2026-03-24 13:52:32 +00:00
717096df8a Fixed aria labels for organisation join/leave buttons 2026-03-12 13:58:53 +00:00
ca49b76cb0 Fixed log message for "rejected" organisation users 2026-02-16 16:38:37 +00:00
dc1ca5c14c Accessibility updates 2026-02-10 11:08:02 +00:00
c95d4708a8 Upgrade to Twig 3.0 (required for php8.4 support) 2026-01-13 15:11:15 +00:00
8cc8448e18 Fixed activity type for "denied" organisations 2025-01-20 16:52:27 +00:00
f143ef9732 Fixed organisations causing errors with user sorting thanks to a distinct() 2023-11-02 16:17:47 +00:00
606154ff24 Make organisation filtering case-insensitive 2023-11-02 16:15:10 +00:00
8cf7370cae Allow changing the case of name of an organisation only 2023-10-16 13:30:47 +01:00
bf2a772566 Added user admin permissions 2023-10-06 08:45:12 +01:00
ddb7e645a0 Fixed filtering of the merge dialog 2023-10-04 15:59:49 +01:00
544b4fab13 Uplifted database version to 1.0.0 2023-09-25 14:33:09 +01:00
74dd06a36c Fix syntax error in permission string 2023-09-13 09:08:25 +01:00
b3b4c19e6d Another attempt to fix some permissions 2023-09-13 09:03:59 +01:00
7fab295b6f Fixed some permission issues 2023-09-12 16:02:00 +01:00
dead350676 Tighten organisation admin permissions & password reset workflow 2023-09-07 11:53:39 +01:00
f3af94a285 Fixed a bug in organisation admin permission check 2023-09-07 10:13:51 +01:00
daa4e78a27 Fixed check for has_organisation 2023-08-23 08:39:27 +01:00
1e0f2017f6 Fixed static function trait 2023-08-23 08:39:10 +01:00
40 changed files with 394 additions and 105 deletions

View File

@@ -1,8 +1,15 @@
.user-organisation-button {
font-size: 12pt;
background-color: #275D8B;
font-weight: bolder;
}
.organisation-admin { .organisation-admin {
color: #56d773 !important; color: #8BE49F !important;
/* color: #56d773 !important; */
} }
.organisation-pending { .organisation-pending {
background-color: #6c757d !important; background-color: #CED2D4 !important;
} }
.membership-pending { .membership-pending {
color: #ffd24a !important; color: #ffd24a !important;

View File

@@ -137,6 +137,33 @@ function bindMemberButtons(el, options) {
}); });
}); });
}); });
// Reset member password button
el.find('.js-member-password').click(function(e) {
e.preventDefault();
var userName = $(this).data('user_name');
$("body").ufModal({
sourceUrl: site.uri.public + '/modals/organisations/o/' + $(this).data('slug') + '/members/reset-password',
ajaxParams: {
slug: $(this).data('slug'),
user_name: $(this).data('user_name')
},
msgTarget: $("#alerts-page")
});
$("body").on('renderSuccess.ufModal', function() {
var modal = $(this).ufModal('getModal');
var form = modal.find('.js-form');
form.ufForm()
.on("submitSuccess.ufForm", function() {
// Navigate or reload page on success
window.location.reload();
});
});
});
} }
// function bindMemberCreationButton(el) { // function bindMemberCreationButton(el) {

View File

@@ -189,6 +189,13 @@ function bindOrganisationButtons(el, options) {
var options = { var options = {
ajax: { ajax: {
url: site.uri.public + '/api/organisations', url: site.uri.public + '/api/organisations',
data: function (params) {
return {
filters: {
info : params.term
}
};
},
processResults: function (data) { processResults: function (data) {
var items = data.rows.filter((i) => i.slug != organisation_slug); var items = data.rows.filter((i) => i.slug != organisation_slug);
return { return {

View File

@@ -51,7 +51,7 @@ return [
'DELETE_YES' => 'Yes, delete organisation', 'DELETE_YES' => 'Yes, delete organisation',
'DELETION_SUCCESSFUL' => 'Successfully deleted organisation <strong>{{name}}</strong>', 'DELETION_SUCCESSFUL' => 'Successfully deleted organisation <strong>{{name}}</strong>',
'MEMBER_COUNT' => '# Members <sub>(excl admins)</sub>', 'MEMBER_COUNT' => '# Members',
'ADMIN_COUNT' => '# Admins', 'ADMIN_COUNT' => '# Admins',
'SELF' => [ 'SELF' => [
@@ -155,6 +155,10 @@ return [
'DEMOTE_CONFIRM_EXTRA' => 'Once demoted they will no longer be able to manage members and agents on the organisation\'s behalf.', 'DEMOTE_CONFIRM_EXTRA' => 'Once demoted they will no longer be able to manage members and agents on the organisation\'s behalf.',
'DEMOTE_YES' => 'Yes, demote administrator', 'DEMOTE_YES' => 'Yes, demote administrator',
'DEMOTE_SUCCESSFUL' => 'Successfully demoted administrator <strong>{{user_name}}</strong> from being an administrator of organisation <strong>{{name}}</strong>', 'DEMOTE_SUCCESSFUL' => 'Successfully demoted administrator <strong>{{user_name}}</strong> from being an administrator of organisation <strong>{{name}}</strong>',
'RESET_PASSWORD' => 'Send password reset link',
'SEND_PASSWORD_LINK_CONFIRM' => 'Please confirm that you wish to send a password reset link to:<br><br> <strong>{{user_name}}</strong> ({{email}}).',
'PASSWORD_LINK_SENT' => 'A password reset link has successfully been sent to <strong>{{email}}</strong>.'
], ],
], ],
@@ -168,7 +172,7 @@ return [
'DEMOTE' => 'Demote to member', 'DEMOTE' => 'Demote to member',
'EDIT' => 'Edit member', 'EDIT' => 'Edit member',
'CHANGE_PASSWORD' => 'Change member password', 'RESET_PASSWORD' => 'Send password reset link',
], ],
'ADMIN' => [ 'ADMIN' => [
@@ -201,6 +205,8 @@ return [
'VIEW_DELETED' => 'View deleted', 'VIEW_DELETED' => 'View deleted',
'DELETED' => 'Deleted', 'DELETED' => 'Deleted',
'RETURN' => 'Return', 'RETURN' => 'Return',
'ACTIONS_FOR' => 'Actions for',
'JOIN' => [ 'JOIN' => [
1 => 'Join', 1 => 'Join',

View File

@@ -33,6 +33,8 @@ $app->group('/api/organisations/o/{slug}/members', function () {
$this->put('/m/{user_name}/promote', 'UserFrosting\Sprinkle\Organisations\Controller\OrganisationMembersController:promote'); $this->put('/m/{user_name}/promote', 'UserFrosting\Sprinkle\Organisations\Controller\OrganisationMembersController:promote');
$this->put('/m/{user_name}/demote', 'UserFrosting\Sprinkle\Organisations\Controller\OrganisationMembersController:demote'); $this->put('/m/{user_name}/demote', 'UserFrosting\Sprinkle\Organisations\Controller\OrganisationMembersController:demote');
$this->post('/m/{user_name}/password-reset', 'UserFrosting\Sprinkle\Organisations\Controller\OrganisationMembersController:createPasswordReset');
})->add('authGuard')->add(new NoCache()); })->add('authGuard')->add(new NoCache());
@@ -45,4 +47,5 @@ $app->group('/modals/organisations/o/{slug}/members', function () {
$this->get('/confirm-reject', 'UserFrosting\Sprinkle\Organisations\Controller\OrganisationMembersController:getModalConfirmReject'); $this->get('/confirm-reject', 'UserFrosting\Sprinkle\Organisations\Controller\OrganisationMembersController:getModalConfirmReject');
$this->get('/confirm-promote', 'UserFrosting\Sprinkle\Organisations\Controller\OrganisationMembersController:getModalConfirmPromote'); $this->get('/confirm-promote', 'UserFrosting\Sprinkle\Organisations\Controller\OrganisationMembersController:getModalConfirmPromote');
$this->get('/confirm-demote', 'UserFrosting\Sprinkle\Organisations\Controller\OrganisationMembersController:getModalConfirmDemote'); $this->get('/confirm-demote', 'UserFrosting\Sprinkle\Organisations\Controller\OrganisationMembersController:getModalConfirmDemote');
$this->get('/reset-password', 'UserFrosting\Sprinkle\Organisations\Controller\OrganisationMembersController:getModalResetPassword');
})->add('authGuard')->add(new NoCache()); })->add('authGuard')->add(new NoCache());

View File

@@ -255,7 +255,7 @@ class OrganisationController extends SimpleController
// Check if name or slug already exists // Check if name or slug already exists
if ( if (
isset($data['name']) && isset($data['name']) &&
$data['name'] != $organisation->name && strtolower($data['name']) != strtolower($organisation->name) &&
$classMapper->getClassMapping('organisation')::findUnique($data['name'], 'name') $classMapper->getClassMapping('organisation')::findUnique($data['name'], 'name')
) { ) {
$ms->addMessageTranslated('danger', 'ORGANISATION.NAME.IN_USE', $data); $ms->addMessageTranslated('danger', 'ORGANISATION.NAME.IN_USE', $data);

View File

@@ -9,6 +9,7 @@
namespace UserFrosting\Sprinkle\Organisations\Controller; namespace UserFrosting\Sprinkle\Organisations\Controller;
use Carbon\Carbon;
use Illuminate\Database\Capsule\Manager as Capsule; use Illuminate\Database\Capsule\Manager as Capsule;
use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ServerRequestInterface as Request;
@@ -918,6 +919,81 @@ class OrganisationMembersController extends SimpleController
return $response->withRedirect($this->ci->router->pathFor('uri_organisation', ['slug' => $organisation->slug])); return $response->withRedirect($this->ci->router->pathFor('uri_organisation', ['slug' => $organisation->slug]));
} }
/**
* Processes the request to send a user a password reset email.
*
* Processes the request from the user update form, checking that:
* 1. The target user's new email address, if specified, is not already in use;
* 2. The logged-in user has the necessary permissions to update the posted field(s);
* 3. We're not trying to disable the master account;
* 4. The submitted data is valid.
* This route requires authentication.
*
* Request type: POST
*
* @param Request $request
* @param Response $response
* @param string[] $args
*
* @throws NotFoundException If user is not found
* @throws ForbiddenException If user is not authorized to access page
*/
public function createPasswordReset(Request $request, Response $response, array $args)
{
/** @var \UserFrosting\Sprinkle\Account\Authorize\AuthorizationManager $authorizer */
$authorizer = $this->ci->authorizer;
/** @var \UserFrosting\Support\Repository\Repository $config */
$config = $this->ci->config;
/** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */
$currentUser = $this->ci->currentUser;
/** @var \UserFrosting\Sprinkle\Core\Alert\AlertStream $ms */
$ms = $this->ci->alerts;
// Get the username from the URL
$user = $this->getUserFromParams($args);
if (!$user) {
throw new NotFoundException();
}
// Access-controlled resource - check that currentUser has permission to edit "password" for this user
if (!$authorizer->checkAccess($currentUser, 'update_user_field', [
'user' => $user,
'fields' => ['password'],
])) {
throw new ForbiddenException();
}
// Begin transaction - DB will be rolled back if an exception occurs
Capsule::transaction(function () use ($user, $config) {
// Create a password reset and shoot off an email
$passwordReset = $this->ci->repoPasswordReset->create($user, $config['password_reset.timeouts.reset']);
// Create and send welcome email with password set link
$message = new TwigMailMessage($this->ci->view, 'mail/password-reset.html.twig');
$message->from($config['address_book.admin'])
->addEmailRecipient(new EmailRecipient($user->email, $user->full_name))
->addParams([
'user' => $user,
'token' => $passwordReset->getToken(),
'request_date' => Carbon::now()->format('Y-m-d H:i:s'),
]);
$this->ci->mailer->send($message);
});
$ms->addMessageTranslated('success', 'ORGANISATION.MEMBER.PASSWORD_LINK_SENT', [
'email' => $user->email,
]);
return $response->withJson([], 200);
}
/** /**
* Returns a list of organisation members. * Returns a list of organisation members.
@@ -1359,6 +1435,60 @@ class OrganisationMembersController extends SimpleController
]); ]);
} }
/**
* Renders the modal form for sending a password reset to a member.
*
* This does NOT render a complete page. Instead, it renders the HTML for the form, which can be embedded in other pages.
* This page requires authentication.
*
* Request type: GET
*
* @param Request $request
* @param Response $response
* @param string[] $args
*
* @throws NotFoundException If user is not found
* @throws ForbiddenException If user is not authorized to access page
*/
public function getModalResetPassword(Request $request, Response $response, array $args)
{
/** @var \UserFrosting\Sprinkle\Account\Authorize\AuthorizationManager $authorizer */
$authorizer = $this->ci->authorizer;
/** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */
$currentUser = $this->ci->currentUser;
/** @var \UserFrosting\Support\Repository\Repository $config */
$config = $this->ci->config;
// GET parameters
$params = $request->getQueryParams();
$user = $this->getUserFromParams($params);
$organisation = $this->getOrganisationFromParams($params);
// Check organisation & user exists
if (!$organisation || !$user) {
throw new NotFoundException();
}
// Access-controlled resource - check that currentUser has permission to edit "password" field for this user
if (!$authorizer->checkAccess($currentUser, 'update_user_field', [
'organisation' => $organisation,
'user' => $user,
'fields' => ['password'],
])) {
throw new ForbiddenException();
}
return $this->ci->view->render($response, 'modals/member-reset-password.html.twig', [
'user' => $user,
'organisation' => $organisation,
'page' => [],
]);
}
/** /**
* Send approval email for specified organisation and confirmation to user. * Send approval email for specified organisation and confirmation to user.
@@ -1516,7 +1646,7 @@ class OrganisationMembersController extends SimpleController
$this->sendRejectedEmail($requester, $organisation); $this->sendRejectedEmail($requester, $organisation);
$this->ci->userActivityLogger->info("User {$currentUser->user_name} rejected the request for user {$requester->user_name} to join organisation {$organisation->name}.", [ $this->ci->userActivityLogger->info("User {$currentUser->user_name} rejected the request for user {$requester->user_name} to join organisation {$organisation->name}.", [
'type' => 'organisation_member_approved', 'type' => 'organisation_member_rejected',
'user_id' => $currentUser->id, 'user_id' => $currentUser->id,
]); ]);

View File

@@ -462,7 +462,7 @@ class OrganisationRegistrationController extends SimpleController
// Record the event in the activity log // Record the event in the activity log
$this->ci->userActivityLogger->info("User {$currentUser->user_name} denied the registration request for organisation {$organisation->name}.", [ $this->ci->userActivityLogger->info("User {$currentUser->user_name} denied the registration request for organisation {$organisation->name}.", [
'type' => 'organisation_approved', 'type' => 'organisation_denied',
'user_id' => $currentUser->id, 'user_id' => $currentUser->id,
]); ]);
}); });
@@ -552,7 +552,7 @@ class OrganisationRegistrationController extends SimpleController
// Record the event in the activity log // Record the event in the activity log
$this->ci->userActivityLogger->info("User {$currentUser->user_name} denied the registration request for organisation {$organisation->name}.", [ $this->ci->userActivityLogger->info("User {$currentUser->user_name} denied the registration request for organisation {$organisation->name}.", [
'type' => 'organisation_approved', 'type' => 'organisation_denied',
'user_id' => $currentUser->id, 'user_id' => $currentUser->id,
]); ]);
}); });

View File

@@ -7,7 +7,7 @@
* @license https://git.avsdev.uk/avsdev/sprinkle-organisations/blob/master/LICENSE.md (LGPL-3.0 License) * @license https://git.avsdev.uk/avsdev/sprinkle-organisations/blob/master/LICENSE.md (LGPL-3.0 License)
*/ */
namespace UserFrosting\Sprinkle\Organisations\Database\Migrations\v010; namespace UserFrosting\Sprinkle\Organisations\Database\Migrations\v1_0_0;
use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Blueprint;
use UserFrosting\Sprinkle\Core\Database\Migration; use UserFrosting\Sprinkle\Core\Database\Migration;
@@ -25,7 +25,7 @@ class OrganisationApprovalsTable extends Migration
* {@inheritdoc} * {@inheritdoc}
*/ */
public static $dependencies = [ public static $dependencies = [
'\UserFrosting\Sprinkle\Account\Database\Migrations\v400\UsersTable', '\UserFrosting\Sprinkle\Account\Database\Migrations\v430\UpdateUsersTable',
]; ];
/** /**

View File

@@ -7,7 +7,7 @@
* @license https://git.avsdev.uk/avsdev/sprinkle-organisations/blob/master/LICENSE.md (LGPL-3.0 License) * @license https://git.avsdev.uk/avsdev/sprinkle-organisations/blob/master/LICENSE.md (LGPL-3.0 License)
*/ */
namespace UserFrosting\Sprinkle\Organisations\Database\Migrations\v010; namespace UserFrosting\Sprinkle\Organisations\Database\Migrations\v1_0_0;
use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Blueprint;
use UserFrosting\Sprinkle\Organisations\Database\Models\Organisation; use UserFrosting\Sprinkle\Organisations\Database\Models\Organisation;
@@ -29,8 +29,8 @@ class OrganisationMembersTable extends Migration
* {@inheritdoc} * {@inheritdoc}
*/ */
public static $dependencies = [ public static $dependencies = [
'\UserFrosting\Sprinkle\Account\Database\Migrations\v400\UsersTable', '\UserFrosting\Sprinkle\Account\Database\Migrations\v430\UpdateUsersTable',
'\UserFrosting\Sprinkle\Organisations\Database\Migrations\v010\OrganisationsTable', '\UserFrosting\Sprinkle\Organisations\Database\Migrations\v1_0_0\OrganisationsTable',
]; ];
/** /**

View File

@@ -7,7 +7,7 @@
* @license https://git.avsdev.uk/avsdev/sprinkle-organisations/blob/master/LICENSE.md (LGPL-3.0 License) * @license https://git.avsdev.uk/avsdev/sprinkle-organisations/blob/master/LICENSE.md (LGPL-3.0 License)
*/ */
namespace UserFrosting\Sprinkle\Organisations\Database\Migrations\v010; namespace UserFrosting\Sprinkle\Organisations\Database\Migrations\v1_0_0;
use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Blueprint;
use UserFrosting\Sprinkle\Core\Database\Migration; use UserFrosting\Sprinkle\Core\Database\Migration;
@@ -25,7 +25,7 @@ class OrganisationMembershipApprovalsTable extends Migration
* {@inheritdoc} * {@inheritdoc}
*/ */
public static $dependencies = [ public static $dependencies = [
'\UserFrosting\Sprinkle\Account\Database\Migrations\v400\UsersTable', '\UserFrosting\Sprinkle\Account\Database\Migrations\v430\UpdateUsersTable',
]; ];
/** /**

View File

@@ -7,7 +7,7 @@
* @license https://git.avsdev.uk/avsdev/sprinkle-organisations/blob/master/LICENSE.md (LGPL-3.0 License) * @license https://git.avsdev.uk/avsdev/sprinkle-organisations/blob/master/LICENSE.md (LGPL-3.0 License)
*/ */
namespace UserFrosting\Sprinkle\Organisations\Database\Migrations\v010; namespace UserFrosting\Sprinkle\Organisations\Database\Migrations\v1_0_0;
use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Blueprint;
use UserFrosting\Sprinkle\Organisations\Database\Models\Organisation; use UserFrosting\Sprinkle\Organisations\Database\Models\Organisation;
@@ -27,7 +27,7 @@ class OrganisationsTable extends Migration
* {@inheritdoc} * {@inheritdoc}
*/ */
public static $dependencies = [ public static $dependencies = [
'\UserFrosting\Sprinkle\Account\Database\Migrations\v400\UsersTable', '\UserFrosting\Sprinkle\Account\Database\Migrations\v430\UpdateUsersTable',
]; ];
/** /**

View File

@@ -124,7 +124,7 @@ trait UserOrganisations {
} }
public function bootUserOrganisations() static public function bootUserOrganisations()
{ {
static::deleting(function ($user) { static::deleting(function ($user) {
if (!$user->deleteUserOrganisations($user->isForceDeleting())) { if (!$user->deleteUserOrganisations($user->isForceDeleting())) {

View File

@@ -50,6 +50,11 @@ class OrganisationPermissions extends BaseSeed
'organisations-admin' => Role::where('slug', 'organisations-admin')->first()->id, 'organisations-admin' => Role::where('slug', 'organisations-admin')->first()->id,
]; ];
$canAdminOrgUsers = "(has_role(self.id,{$roleIds['organisations-admin']}) || (has_matching_organisation(self.id,user.id,1) && !has_role(user.id,{$roleIds['organisations-admin']})))";
$canAdminOrgAdmins = "(has_role(self.id,{$roleIds['organisations-admin']}) || has_matching_organisation(self.id,user.id,1))";
$excludeMasters = "(!is_master(user.id) && !has_role(user.id,{$roleIds['site-admin']}))";
$isSelf = "equals_num(self.id,user.id)";
return [ return [
'create_organisation' => new Permission([ 'create_organisation' => new Permission([
'slug' => 'create_organisation', 'slug' => 'create_organisation',
@@ -127,12 +132,6 @@ class OrganisationPermissions extends BaseSeed
]), ]),
// 'view_organisation_members_field' => new Permission([
// 'slug' => 'view_organisation_field',
// 'name' => 'View organisation members field',
// 'conditions' => "in(property,['members'])",
// 'description' => 'View members field of any organisation.',
// ]),
'view_organisation_members' => new Permission([ 'view_organisation_members' => new Permission([
'slug' => 'view_organisation_field', 'slug' => 'view_organisation_field',
'name' => 'View organisation members', 'name' => 'View organisation members',
@@ -200,12 +199,12 @@ class OrganisationPermissions extends BaseSeed
]), ]),
// 'uri_user_in_organisation' => new Permission([ 'uri_user_in_organisation' => new Permission([
// 'slug' => 'uri_user', 'slug' => 'uri_user',
// 'name' => 'View user', 'name' => 'View user',
// 'conditions' => "has_matching_organisation(self.id,user.id,true) && !is_master(user.id) && !has_role(user.id,{$roleIds['site-admin']}) && (!has_role(user.id,{$roleIds['organisations-admin']}) || equals_num(self.id,user.id))", 'conditions' => "(($canAdminOrgAdmins && $excludeMasters) || $isSelf)",
// 'description' => 'View the user page of any user in your group, except the master user and Site and (global) Organisation Administrators (except yourself).', 'description' => 'View the user page of any user in your orgnisation, except the master user and Site and (global) Organisation Administrators (except yourself).',
// ]), ]),
'view_user_field' => new Permission([ 'view_user_field' => new Permission([
'slug' => 'view_user_field', 'slug' => 'view_user_field',
'name' => 'View user', 'name' => 'View user',
@@ -215,35 +214,43 @@ class OrganisationPermissions extends BaseSeed
'update_user_field' => new Permission([ 'update_user_field' => new Permission([
'slug' => 'update_user_field', 'slug' => 'update_user_field',
'name' => 'Edit user', 'name' => 'Edit user',
'conditions' => "!has_role(user.id,{$roleIds['site-admin']}) && subset(fields,['organisations'])", 'conditions' => "$excludeMasters && subset(fields,['organisations'])",
'description' => 'Edit organisations for users who are not Site Administrators.', 'description' => 'Edit organisations for users who are not Site Administrators.',
]), ]),
'view_user_field_group' => new Permission([ 'view_user_field_group' => new Permission([
'slug' => 'view_user_field', 'slug' => 'view_user_field',
'name' => 'View user', 'name' => 'View user',
'conditions' => "equals_num(self.group_id,user.group_id) && !is_master(user.id) && !has_role(user.id,{$roleIds['site-admin']}) && (!has_role(user.id,{$roleIds['group-admin']}) || equals_num(self.id,user.id)) && in(property,['organisations'])", 'conditions' => "equals_num(self.group_id,user.group_id) && $excludeMasters && (!has_role(user.id,{$roleIds['group-admin']}) || equals_num(self.id,user.id)) && in(property,['organisations'])",
'description' => 'View organisations of any user in your own group, except the master user and Site and Group Administrators (except yourself).', 'description' => 'View organisations of any user in your own group, except the master user and Site and Group Administrators (except yourself).',
]), ]),
'update_user_field_group' => new Permission([ 'update_user_field_group' => new Permission([
'slug' => 'update_user_field', 'slug' => 'update_user_field',
'name' => 'Edit group user', 'name' => 'Edit group user',
'conditions' => "equals_num(self.group_id,user.group_id) && !is_master(user.id) && !has_role(user.id,{$roleIds['site-admin']}) && (!has_role(user.id,{$roleIds['group-admin']}) || equals_num(self.id,user.id)) && subset(fields,['organisations'])", 'conditions' => "equals_num(self.group_id,user.group_id) && $excludeMasters && (!has_role(user.id,{$roleIds['group-admin']}) || equals_num(self.id,user.id)) && subset(fields,['organisations'])",
'description' => 'Edit organisations for users in your own group who are not Site or Group Administrators, except yourself.', 'description' => 'Edit organisations for users in your own group who are not Site or Group Administrators, except yourself.',
]), ]),
'view_user_field_organisation' => new Permission([ 'view_user_field_organisation_audit' => new Permission([
'slug' => 'view_user_field', 'slug' => 'view_user_field',
'name' => 'View user', 'name' => 'View user',
'conditions' => "has_matching_organisation(self.id,user.id) && !is_master(user.id) && !has_role(user.id,{$roleIds['site-admin']}) && (!has_role(user.id,{$roleIds['organisations-admin']}) || equals_num(self.id,user.id)) && in(property,['user_name','name','email','locale','roles','group','activities','organisations'])", 'conditions' => "(($canAdminOrgUsers && $excludeMasters) || $isSelf) && in(property,['activities'])",
'description' => 'View certain properties of any user in your own organisation, except the master user and Site and (global) Organisation Administrators (except yourself).', 'description' => 'View certain properties of any user in your own organisation, except the master user and Site and (global) Organisation Administrators (except yourself).',
]), ]),
'update_user_field_organisation' => new Permission([ 'update_user_field_organisation' => new Permission([
'slug' => 'update_user_field', 'slug' => 'update_user_field',
'name' => 'Edit organisation user', 'name' => 'Edit organisation user',
'conditions' => "has_matching_organisation(self.id,user.id,true) && !is_master(user.id) && !has_role(user.id,{$roleIds['site-admin']}) && (!has_role(user.id,{$roleIds['organisations-admin']}) || equals_num(self.id,user.id)) && subset(fields,['name','email','locale','flag_enabled','flag_verified','password'])",
'conditions' => "(($canAdminOrgUsers && $excludeMasters) || $isSelf) && subset(fields,['name','email','locale','flag_enabled','flag_verified','password'])",
'description' => 'Edit users in your own organisation who are not Site or (global) Organisation Administrators, except yourself.', 'description' => 'Edit users in your own organisation who are not Site or (global) Organisation Administrators, except yourself.',
]), ]),
'view_user_field_organisation' => new Permission([
'slug' => 'view_user_field',
'name' => 'View user',
'conditions' => "(($canAdminOrgUsers && $excludeMasters) || $isSelf) && in(property,['user_name','name','email','locale','roles','group','organisations'])",
'description' => 'View certain properties of any user in your own organisation, except the master user and Site and (global) Organisation Administrators (except yourself).',
]),
]; ];
} }
@@ -304,6 +311,14 @@ class OrganisationPermissions extends BaseSeed
]); ]);
} }
$roleUserAdmin = Role::where('slug', 'user-admin')->first();
if ($roleSiteAdmin) {
$roleSiteAdmin->permissions()->syncWithoutDetaching([
$permissions['view_user_field']->id,
$permissions['update_user_field']->id,
]);
}
$roleGroupAdmin = Role::where('slug', 'group-admin')->first(); $roleGroupAdmin = Role::where('slug', 'group-admin')->first();
if ($roleGroupAdmin) { if ($roleGroupAdmin) {
$roleGroupAdmin->permissions()->sync([ $roleGroupAdmin->permissions()->sync([
@@ -328,13 +343,15 @@ class OrganisationPermissions extends BaseSeed
$permissions['uri_organisation']->id, $permissions['uri_organisation']->id,
$permissions['uri_organisations']->id, $permissions['uri_organisations']->id,
$permissions['uri_user_in_organisation']->id,
$permissions['uri_deleted_organisations']->id, $permissions['uri_deleted_organisations']->id,
$permissions['view_organisation_members']->id, $permissions['view_organisation_members']->id,
$permissions['promote_organisation_member']->id, $permissions['promote_organisation_member']->id,
#$permissions['view_user_field']->id, $permissions['view_user_field_organisation_audit']->id,
#$permissions['update_user_field']->id, $permissions['view_user_field_organisation']->id,
$permissions['update_user_field_organisation']->id,
]); ]);
} }
@@ -352,6 +369,7 @@ class OrganisationPermissions extends BaseSeed
$permissions['uri_organisation_own']->id, $permissions['uri_organisation_own']->id,
$permissions['uri_organisations']->id, $permissions['uri_organisations']->id,
$permissions['uri_user_in_organisation']->id,
$permissions['view_user_field_organisation']->id, $permissions['view_user_field_organisation']->id,
$permissions['update_user_field_organisation']->id, $permissions['update_user_field_organisation']->id,

View File

@@ -67,8 +67,10 @@ class ServicesProvider
*/ */
$authorizer->addCallback('has_organisation', function ($user_id) { $authorizer->addCallback('has_organisation', function ($user_id) {
$query = Capsule::table('organisation_members') $query = Capsule::table('organisation_members')
->join('organisations', 'organisation_members.organisation_id', 'organisations.id')
->where('user_id', $user_id) ->where('user_id', $user_id)
->where('flag_approved', true); ->where('organisation_members.flag_approved', true)
->where('organisations.flag_approved', true);
return $query->count() > 0; return $query->count() > 0;
}); });
@@ -101,11 +103,12 @@ class ServicesProvider
* @return bool true if $user is an administrator of $organisation. * @return bool true if $user is an administrator of $organisation.
*/ */
$authorizer->addCallback('is_organisation_admin', function ($user_id, $organisation_id) { $authorizer->addCallback('is_organisation_admin', function ($user_id, $organisation_id) {
return Capsule::table('organisation_members') $query = Capsule::table('organisation_members')
->where('user_id', $user_id) ->where('user_id', $user_id)
->where('organisation_id', $organisation_id) ->where('organisation_id', $organisation_id)
->where('flag_admin', true) ->where('flag_admin', true);
->count() > 0;
return $query->count() > 0;
}); });
/* /*

View File

@@ -12,7 +12,7 @@ namespace UserFrosting\Sprinkle\Organisations\Sprunje;
use Illuminate\Database\Schema\Builder; use Illuminate\Database\Schema\Builder;
use UserFrosting\Sprinkle\Core\Facades\Translator; use UserFrosting\Sprinkle\Core\Facades\Translator;
use UserFrosting\Sprinkle\Core\Sprunje\Sprunje; use UserFrosting\Sprinkle\Core\Sprunje\Sprunje;
use UserFrosting\Sprinkle\Admin\Sprunje\UserSprunje as UFUserSprunje; use UserFrosting\Sprinkle\UFTweaks\Sprunje\UserSprunje as UFUserSprunje;
/** /**
* UserSprunje. * UserSprunje.
@@ -29,8 +29,10 @@ class UserSprunje extends UFUserSprunje
'last_activity', 'last_activity',
'status', 'status',
]; ];
protected $sortable = [ protected $sortable = [
'name', 'name',
'organisations',
'last_activity', 'last_activity',
'status', 'status',
]; ];
@@ -56,6 +58,7 @@ class UserSprunje extends UFUserSprunje
*/ */
protected function sortOrganisations($query, $direction) protected function sortOrganisations($query, $direction)
{ {
$query = $query->addSelect('organisations.name');
$query->orderBy('organisations.name', $direction); $query->orderBy('organisations.name', $direction);
return $this; return $this;
@@ -75,13 +78,64 @@ class UserSprunje extends UFUserSprunje
$values = explode($this->orSeparator, $value); $values = explode($this->orSeparator, $value);
$query->where(function ($query) use ($values) { $query->where(function ($query) use ($values) {
foreach ($values as $value) { foreach ($values as $value) {
$query->orLike('organisations.name', $value); $likeValue = '%' . mb_strtolower($value) . '%';
$query->orWhereRaw('LOWER(organisations.name) LIKE ?', $likeValue);
} }
}); });
return $this; return $this;
} }
/**
* Sort based on last activity time.
*
* @param Builder $query
* @param string $direction
*
* @return self
*/
protected function sortLastActivity($query, $direction)
{
$query = $query->addSelect('activities.occurred_at');
$query->orderBy('activities.occurred_at', $direction);
return $this;
}
/**
* Sort based on last name.
*
* @param Builder $query
* @param string $direction
*
* @return self
*/
protected function sortName($query, $direction)
{
$query = $query->addSelect('last_name');
$query = $query->addSelect('first_name');
$query->orderBy('last_name', $direction)->orderBy('first_name', $direction);
return $this;
}
/**
* Sort active, unactivated, disabled.
*
* @param Builder $query
* @param string $direction
*
* @return self
*/
protected function sortStatus($query, $direction)
{
$query = $query->addSelect('flag_enabled');
$query = $query->addSelect('flag_verified');
$query->orderBy('flag_enabled', $direction)->orderBy('flag_verified', $direction);
return $this;
}
/** /**
* Get the unpaginated count of items (before filtering) in this query. * Get the unpaginated count of items (before filtering) in this query.
* *

View File

@@ -77,7 +77,7 @@ class OrganisationsExtension extends AbstractExtension implements GlobalsInterfa
]; ];
} }
public function getGlobals() public function getGlobals(): array
{ {
$config = $this->services->config['organisation']; $config = $this->services->config['organisation'];

View File

@@ -7,10 +7,10 @@
{% include "forms/csrf.html.twig" %} {% include "forms/csrf.html.twig" %}
<div class="js-form-alerts"> <div class="js-form-alerts">
</div> </div>
<h4> <p>
{{translate("ORGANISATION.JOIN_REQUEST.ACCEPT_CONFIRM", {name: organisation.name, agent_name: agent.name})}}<br> {{translate("ORGANISATION.JOIN_REQUEST.ACCEPT_CONFIRM", {name: organisation.name, agent_name: agent.name})}}<br>
<small>{{translate("ORGANISATION.JOIN_REQUEST.ACCEPT_CONFIRM_EXTRA", {name: organisation.name, agent_name: agent.name})}}</small> <small>{{translate("ORGANISATION.JOIN_REQUEST.ACCEPT_CONFIRM_EXTRA", {name: organisation.name, agent_name: agent.name})}}</small>
</h4> </p>
<br> <br>
<div class="btn-group-action"> <div class="btn-group-action">
<button type="submit" class="btn btn-success btn-lg btn-block">{{translate("ORGANISATION.JOIN_REQUEST.ACCEPT_YES")}}</button> <button type="submit" class="btn btn-success btn-lg btn-block">{{translate("ORGANISATION.JOIN_REQUEST.ACCEPT_YES")}}</button>

View File

@@ -7,7 +7,7 @@
{% include "forms/csrf.html.twig" %} {% include "forms/csrf.html.twig" %}
<div class="js-form-alerts"> <div class="js-form-alerts">
</div> </div>
<h4>{{translate("ORGANISATION.JOIN_REQUEST.CANCEL_CONFIRM", {name: organisation.name})}}{% if delete_hard %}<br><small>{{translate("ACTION_CANNOT_UNDONE")}}</small>{% endif %}</h4> <p>{{translate("ORGANISATION.JOIN_REQUEST.CANCEL_CONFIRM", {name: organisation.name})}}{% if delete_hard %}<br><small>{{translate("ACTION_CANNOT_UNDONE")}}</small>{% endif %}</p>
<br> <br>
<div class="btn-group-action"> <div class="btn-group-action">
<button type="submit" class="btn btn-danger btn-lg btn-block">{{translate("ORGANISATION.JOIN_REQUEST.CANCEL_YES")}}</button> <button type="submit" class="btn btn-danger btn-lg btn-block">{{translate("ORGANISATION.JOIN_REQUEST.CANCEL_YES")}}</button>

View File

@@ -7,7 +7,7 @@
{% include "forms/csrf.html.twig" %} {% include "forms/csrf.html.twig" %}
<div class="js-form-alerts"> <div class="js-form-alerts">
</div> </div>
<h4>{{translate("ORGANISATION.REGISTRATION.CANCEL_CONFIRM", {name: organisation.name})}}{% if delete_hard %}<br><small>{{translate("ACTION_CANNOT_UNDONE")}}</small>{% endif %}</h4> <p>{{translate("ORGANISATION.REGISTRATION.CANCEL_CONFIRM", {name: organisation.name})}}{% if delete_hard %}<br><small>{{translate("ACTION_CANNOT_UNDONE")}}</small>{% endif %}</p>
<br> <br>
<div class="btn-group-action"> <div class="btn-group-action">
<button type="submit" class="btn btn-danger btn-lg btn-block">{{translate("ORGANISATION.REGISTRATION.CANCEL_YES")}}</button> <button type="submit" class="btn btn-danger btn-lg btn-block">{{translate("ORGANISATION.REGISTRATION.CANCEL_YES")}}</button>

View File

@@ -7,7 +7,7 @@
{% include "forms/csrf.html.twig" %} {% include "forms/csrf.html.twig" %}
<div class="js-form-alerts"> <div class="js-form-alerts">
</div> </div>
<h4>{{translate("ORGANISATION.DELETE_CONFIRM", {name: organisation.name})}}{% if delete_hard %}<br><small>{{translate("DELETE_CANNOT_UNDONE")}}</small>{% endif %}</h4> <p>{{translate("ORGANISATION.DELETE_CONFIRM", {name: organisation.name})}}{% if delete_hard %}<br><small>{{translate("DELETE_CANNOT_UNDONE")}}</small>{% endif %}</p>
<br> <br>
<div class="btn-group-action"> <div class="btn-group-action">
<button type="submit" class="btn btn-danger btn-lg btn-block">{{translate("ORGANISATION.DELETE_YES")}}</button> <button type="submit" class="btn btn-danger btn-lg btn-block">{{translate("ORGANISATION.DELETE_YES")}}</button>

View File

@@ -7,7 +7,7 @@
{% include "forms/csrf.html.twig" %} {% include "forms/csrf.html.twig" %}
<div class="js-form-alerts"> <div class="js-form-alerts">
</div> </div>
<h4>{{translate("ORGANISATION.MEMBER.DEMOTE_CONFIRM", {user_name: user.user_name, name: organisation.name})}}<br><small>{{translate("ORGANISATION.MEMBER.DEMOTE_CONFIRM_EXTRA")}}</small></h4> <p>{{translate("ORGANISATION.MEMBER.DEMOTE_CONFIRM", {user_name: user.user_name, name: organisation.name})}}<br><small>{{translate("ORGANISATION.MEMBER.DEMOTE_CONFIRM_EXTRA")}}</small></p>
<br> <br>
<div class="btn-group-action"> <div class="btn-group-action">
<button type="submit" class="btn btn-danger btn-lg btn-block">{{translate("ORGANISATION.MEMBER.DEMOTE_YES")}}</button> <button type="submit" class="btn btn-danger btn-lg btn-block">{{translate("ORGANISATION.MEMBER.DEMOTE_YES")}}</button>

View File

@@ -8,12 +8,12 @@
<div class="js-form-alerts"> <div class="js-form-alerts">
</div> </div>
{% if approval_required %} {% if approval_required %}
<h4> <p>
{{translate("ORGANISATION.JOIN_REQUEST.REQUEST_CONFIRM", {name: organisation.name})}} {{translate("ORGANISATION.JOIN_REQUEST.REQUEST_CONFIRM", {name: organisation.name})}}
<small>{{translate("ORGANISATION.JOIN_REQUEST.APPROVAL_REQUIRED")}}</small> <small>{{translate("ORGANISATION.JOIN_REQUEST.APPROVAL_REQUIRED")}}</small>
</h4> </p>
{% else %} {% else %}
<h4>{{translate("ORGANISATION.JOIN_CONFIRM", {name: organisation.name})}}</h4> <p>{{translate("ORGANISATION.JOIN_CONFIRM", {name: organisation.name})}}</p>
{% endif %} {% endif %}
<br> <br>
<div class="btn-group-action"> <div class="btn-group-action">

View File

@@ -7,7 +7,7 @@
{% include "forms/csrf.html.twig" %} {% include "forms/csrf.html.twig" %}
<div class="js-form-alerts"> <div class="js-form-alerts">
</div> </div>
<h4>{{translate("ORGANISATION.LEAVE_CONFIRM", {name: organisation.name})}}<br><small>{{translate("ACTION_CANNOT_UNDONE")}}</small></h4> <p>{{translate("ORGANISATION.LEAVE_CONFIRM", {name: organisation.name})}}<br><small>{{translate("ACTION_CANNOT_UNDONE")}}</small></p>
<br> <br>
<div class="btn-group-action"> <div class="btn-group-action">
<button type="submit" class="btn btn-danger btn-lg btn-block">{{translate("ORGANISATION.LEAVE_YES")}}</button> <button type="submit" class="btn btn-danger btn-lg btn-block">{{translate("ORGANISATION.LEAVE_YES")}}</button>

View File

@@ -7,7 +7,7 @@
{% include "forms/csrf.html.twig" %} {% include "forms/csrf.html.twig" %}
<div class="js-form-alerts"> <div class="js-form-alerts">
</div> </div>
<h4>{{translate("ORGANISATION.PERMENENT_DELETE_CONFIRM", {name: organisation.name})}}<br><small>{{translate("ACTION_CANNOT_UNDONE")}}</small></h4> <p>{{translate("ORGANISATION.PERMENENT_DELETE_CONFIRM", {name: organisation.name})}}<br><small>{{translate("ACTION_CANNOT_UNDONE")}}</small></p>
<br> <br>
<div class="btn-group-action"> <div class="btn-group-action">
<button type="submit" class="btn btn-danger btn-lg btn-block">{{translate("ORGANISATION.PERMENENT_DELETE_YES")}}</button> <button type="submit" class="btn btn-danger btn-lg btn-block">{{translate("ORGANISATION.PERMENENT_DELETE_YES")}}</button>

View File

@@ -7,7 +7,7 @@
{% include "forms/csrf.html.twig" %} {% include "forms/csrf.html.twig" %}
<div class="js-form-alerts"> <div class="js-form-alerts">
</div> </div>
<h4>{{translate("ORGANISATION.MEMBER.PROMOTE_CONFIRM", {user_name: user.user_name, name: organisation.name})}}</h4> <p>{{translate("ORGANISATION.MEMBER.PROMOTE_CONFIRM", {user_name: user.user_name, name: organisation.name})}}</p>
<br> <br>
<p>{{translate("ORGANISATION.MEMBER.PROMOTE_CONFIRM_EXTRA")}}</p> <p>{{translate("ORGANISATION.MEMBER.PROMOTE_CONFIRM_EXTRA")}}</p>
<br> <br>

View File

@@ -7,10 +7,10 @@
{% include "forms/csrf.html.twig" %} {% include "forms/csrf.html.twig" %}
<div class="js-form-alerts"> <div class="js-form-alerts">
</div> </div>
<h4> <p>
{{translate("ORGANISATION.JOIN_REQUEST.REJECT_CONFIRM", {name: organisation.name, agent_name: agent.name})}}<br> {{translate("ORGANISATION.JOIN_REQUEST.REJECT_CONFIRM", {name: organisation.name, agent_name: agent.name})}}<br>
<small>{{translate("ORGANISATION.JOIN_REQUEST.REJECT_CONFIRM_EXTRA", {name: organisation.name, agent_name: agent.name})}}</small> <small>{{translate("ORGANISATION.JOIN_REQUEST.REJECT_CONFIRM_EXTRA", {name: organisation.name, agent_name: agent.name})}}</small>
</h4> </p>
<br> <br>
<div class="btn-group-action"> <div class="btn-group-action">
<button type="submit" class="btn btn-success btn-lg btn-block">{{translate("ORGANISATION.JOIN_REQUEST.REJECT_YES")}}</button> <button type="submit" class="btn btn-success btn-lg btn-block">{{translate("ORGANISATION.JOIN_REQUEST.REJECT_YES")}}</button>

View File

@@ -7,7 +7,7 @@
{% include "forms/csrf.html.twig" %} {% include "forms/csrf.html.twig" %}
<div class="js-form-alerts"> <div class="js-form-alerts">
</div> </div>
<h4>{{translate("ORGANISATION.MEMBER.REMOVE_CONFIRM", {user_name: user.user_name, name: organisation.name})}}<br><small>{{translate("ACTION_CANNOT_UNDONE")}}</small></h4> <p>{{translate("ORGANISATION.MEMBER.REMOVE_CONFIRM", {user_name: user.user_name, name: organisation.name})}}<br><small>{{translate("ACTION_CANNOT_UNDONE")}}</small></p>
<br> <br>
<div class="btn-group-action"> <div class="btn-group-action">
<button type="submit" class="btn btn-danger btn-lg btn-block">{{translate("ORGANISATION.MEMBER.REMOVE_YES")}}</button> <button type="submit" class="btn btn-danger btn-lg btn-block">{{translate("ORGANISATION.MEMBER.REMOVE_YES")}}</button>

View File

@@ -0,0 +1,32 @@
{% extends "modals/modal.html.twig" %}
{% block modal_title %}{{translate("ORGANISATION.MEMBER.RESET_PASSWORD")}}{% endblock %}
{% block modal_body %}
<form class="js-form" method="POST" action="{{site.uri.public}}/api/organisations/o/{{organisation.slug}}/members/m/{{user.user_name}}/password-reset">
{% include "forms/csrf.html.twig" %}
<div class="js-form-alerts">
</div>
<div class="row">
<div class="col-sm-12">
{{translate("ORGANISATION.MEMBER.SEND_PASSWORD_LINK_CONFIRM", {
'user_name': user.user_name,
'email': user.email
})}}
</div>
</div>
<br>
<div class="row">
<div class="col-xs-8 col-sm-4">
<button type="submit" class="btn btn-block btn-lg btn-success">{{translate('CONFIRM')}}</button>
</div>
<div class="col-xs-4 col-sm-3 pull-right">
<button type="button" class="btn btn-block btn-lg btn-link" data-dismiss="modal">{{translate('CANCEL')}}</button>
</div>
</div>
</form>
<!-- Include validation rules -->
<script>
{% include "pages/partials/page.js.twig" %}
</script>
{% endblock %}

View File

@@ -9,7 +9,7 @@
<div class="js-form-alerts"> <div class="js-form-alerts">
</div> </div>
<div class="js-form-organisations"> <div class="js-form-organisations">
<h4>{{translate("ORGANISATION.MERGE_INFORM", {name: organisation.name})}}<br><small>{{translate("MERGE_CANNOT_UNDONE")}}</small></h4> <p>{{translate("ORGANISATION.MERGE_INFORM", {name: organisation.name})}}<br><small>{{translate("MERGE_CANNOT_UNDONE")}}</small></p>
<div class="padding-bottom"> <div class="padding-bottom">
<label>{{translate("MERGE_INTO")}}:</label> <label>{{translate("MERGE_INTO")}}:</label>
<select class="form-control js-select-new" type="text" name="target_slug"></select> <select class="form-control js-select-new" type="text" name="target_slug"></select>

View File

@@ -1,4 +1,4 @@
{% extends "@admin/pages/abstract/dashboard.html.twig" %} {% extends "pages/abstract/dashboard.html.twig" %}
{% block stylesheets_page %} {% block stylesheets_page %}
<!-- Page-specific CSS asset bundle --> <!-- Page-specific CSS asset bundle -->

View File

@@ -1,4 +1,4 @@
{% extends "@admin/pages/abstract/dashboard.html.twig" %} {% extends "pages/abstract/dashboard.html.twig" %}
{% block stylesheets_page %} {% block stylesheets_page %}
<!-- Page-specific CSS asset bundle --> <!-- Page-specific CSS asset bundle -->
@@ -16,12 +16,12 @@
{% block summary %} {% block summary %}
<div id="view-organisation" class="box box-primary"> <div id="view-organisation" class="box box-primary">
<div class="box-header with-border"> <div class="box-header with-border">
<h3 class="box-title">{{translate('ORGANISATION.SUMMARY')}}</h3> <h2 class="box-title">{{translate('ORGANISATION.SUMMARY')}}</h2>
{% block menu_tools %} {% block menu_tools %}
{% if 'tools' not in tools.hidden %} {% if 'tools' not in tools.hidden %}
<div class="box-tools pull-right"> <div class="box-tools pull-right">
<div class="btn-group"> <div class="btn-group">
<button type="button" class="btn btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <button type="button" class="btn btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Expand organisation tools menu">
<i class="fas fa-cog"></i> <span class="caret"></span> <i class="fas fa-cog"></i> <span class="caret"></span>
</button> </button>
<ul class="dropdown-menu box-tool-menu"> <ul class="dropdown-menu box-tool-menu">
@@ -117,7 +117,7 @@
{% block members %} {% block members %}
<div id="widget-organisation-members" class="box box-primary"> <div id="widget-organisation-members" class="box box-primary">
<div class="box-header"> <div class="box-header">
<h3 class="box-title"><i class="fas fa-fw fa-user"></i> {{translate('MEMBER', 2)}}</h3> <h2 class="box-title"><i class="fas fa-fw fa-user"></i> {{translate('MEMBER', 2)}}</h2>
{% include "tables/table-tool-menu.html.twig" %} {% include "tables/table-tool-menu.html.twig" %}
</div> </div>
<div class="box-body"> <div class="box-body">

View File

@@ -1,4 +1,4 @@
{% extends "@admin/pages/abstract/dashboard.html.twig" %} {% extends "pages/abstract/dashboard.html.twig" %}
{% block stylesheets_page %} {% block stylesheets_page %}
<!-- Page-specific CSS asset bundle --> <!-- Page-specific CSS asset bundle -->
@@ -15,7 +15,7 @@
<div class="col-md-12"> <div class="col-md-12">
<div id="widget-organisations" class="box box-primary"> <div id="widget-organisations" class="box box-primary">
<div class="box-header"> <div class="box-header">
<h3 class="box-title"><i class="fas fa-fw fa-sitemap"></i> {{translate('ORGANISATION', 2)}}</h3> <h2 class="box-title"><i class="fas fa-fw fa-sitemap"></i> {{translate('ORGANISATION', 2)}}</h2>
{% include "tables/table-tool-menu.html.twig" %} {% include "tables/table-tool-menu.html.twig" %}
</div> </div>
<div class="box-body"> <div class="box-body">

View File

@@ -168,6 +168,7 @@
{% endblock %} {% endblock %}
</div> </div>
</div> </div>
{% if checkAccess('view_user_field', { 'user': user, 'property': 'activities' }) %}
{% if 'activities' not in widgets.hidden %} {% if 'activities' not in widgets.hidden %}
<div class="col-lg-8"> <div class="col-lg-8">
{% block activity_box %} {% block activity_box %}
@@ -188,6 +189,7 @@
{% endblock %} {% endblock %}
</div> </div>
{% endif %} {% endif %}
{% endif %}
</div> </div>
{% if 'permissions' not in widgets.hidden %} {% if 'permissions' not in widgets.hidden %}
<div class="row"> <div class="row">

View File

@@ -3,45 +3,45 @@
{% verbatim %} {% verbatim %}
<td class="uf-table-fit-width"> <td class="uf-table-fit-width">
<div class="btn-group"> <div class="btn-group">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown">{% endverbatim %}{{translate("ACTIONS")}}{% verbatim %}<span class="caret"></span></button> <button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-label="{% endverbatim %}{{translate("ACTIONS_FOR")}}{% verbatim %} {{row.full_name}} ({{row.user_name}})">{% endverbatim %}{{translate("ACTIONS")}}{% verbatim %}<span class="caret"></span></button>
<ul class="dropdown-menu dropdown-menu-right-responsive" role="menu"> <ul class="dropdown-menu dropdown-menu-right-responsive" role="menu">
{{#ifx row.membership_approved '!=' 1 }} {{#ifx row.membership_approved '!=' 1 }}
<li> <li role="menuitem">
<a href="#" data-slug="{% endverbatim %}{{organisation.slug}}{% verbatim %}" data-user_name="{{row.user_name}}" class="js-member-accept"> <a href="#" data-slug="{% endverbatim %}{{organisation.slug}}{% verbatim %}" data-user_name="{{row.user_name}}" class="js-member-accept" aria-label="{% endverbatim %}{{translate("ORGANISATION.JOIN_REQUEST.ACCEPT")}}{% verbatim %} {{row.full_name}} ({{row.user_name}})">
<i class="fas fa-thumbs-up"></i> {% endverbatim %}{{translate("ORGANISATION.JOIN_REQUEST.ACCEPT")}}{% verbatim %} <i class="fas fa-thumbs-up"></i> {% endverbatim %}{{translate("ORGANISATION.JOIN_REQUEST.ACCEPT")}}{% verbatim %}
</a> </a>
</li> </li>
<li> <li role="menuitem">
<a href="#" data-slug="{% endverbatim %}{{organisation.slug}}{% verbatim %}" data-user_name="{{row.user_name}}" class="js-member-reject"> <a href="#" data-slug="{% endverbatim %}{{organisation.slug}}{% verbatim %}" data-user_name="{{row.user_name}}" class="js-member-reject" aria-label="{% endverbatim %}{{translate("ORGANISATION.JOIN_REQUEST.REJECT")}}{% verbatim %} {{row.full_name}} ({{row.user_name}})">
<i class="fas fa-thumbs-down"></i> {% endverbatim %}{{translate("ORGANISATION.JOIN_REQUEST.REJECT")}}{% verbatim %} <i class="fas fa-thumbs-down"></i> {% endverbatim %}{{translate("ORGANISATION.JOIN_REQUEST.REJECT")}}{% verbatim %}
</a> </a>
</li> </li>
{{ else }} {{ else }}
{{#ifx row.organisation_admin '==' 1 }} {{#ifx row.organisation_admin '==' 1 }}
<li> <li role="menuitem">
<a href="#" data-slug="{% endverbatim %}{{organisation.slug}}{% verbatim %}" data-user_name="{{row.user_name}}" class="js-member-demote"> <a href="#" data-slug="{% endverbatim %}{{organisation.slug}}{% verbatim %}" data-user_name="{{row.user_name}}" class="js-member-demote" aria-label="{% endverbatim %}{{translate("MEMBER.DEMOTE")}}{% verbatim %}: {{row.full_name}} ({{row.user_name}})">
<i class="fas fa-angle-double-down"></i> {% endverbatim %}{{translate("MEMBER.DEMOTE")}}{% verbatim %} <i class="fas fa-angle-double-down"></i> {% endverbatim %}{{translate("MEMBER.DEMOTE")}}{% verbatim %}
</a> </a>
</li> </li>
{{ else }} {{ else }}
<li> <li role="menuitem">
<a href="#" data-slug="{% endverbatim %}{{organisation.slug}}{% verbatim %}" data-user_name="{{row.user_name}}" class="js-member-promote"> <a href="#" data-slug="{% endverbatim %}{{organisation.slug}}{% verbatim %}" data-user_name="{{row.user_name}}" class="js-member-promote" aria-label="{% endverbatim %}{{translate("MEMBER.PROMOTE")}}{% verbatim %}: {{row.full_name}} ({{row.user_name}})">
<i class="fas fa-angle-double-up"></i> {% endverbatim %}{{translate("MEMBER.PROMOTE")}}{% verbatim %} <i class="fas fa-angle-double-up"></i> {% endverbatim %}{{translate("MEMBER.PROMOTE")}}{% verbatim %}
</a> </a>
</li> </li>
{{/ifx}} {{/ifx}}
<li> <li role="menuitem">
<a href="#" data-slug="{% endverbatim %}{{organisation.slug}}{% verbatim %}" data-user_name="{{row.user_name}}" class="js-user-edit"> <a href="#" data-slug="{% endverbatim %}{{organisation.slug}}{% verbatim %}" data-user_name="{{row.user_name}}" class="js-user-edit" aria-label="{% endverbatim %}{{translate("MEMBER.EDIT")}}{% verbatim %}: {{row.full_name}} ({{row.user_name}})">
<i class="fas fa-edit"></i> {% endverbatim %}{{translate("MEMBER.EDIT")}}{% verbatim %} <i class="fas fa-edit"></i> {% endverbatim %}{{translate("MEMBER.EDIT")}}{% verbatim %}
</a> </a>
</li> </li>
<li> <li role="menuitem">
<a href="#" data-slug="{% endverbatim %}{{organisation.slug}}{% verbatim %}" data-user_name="{{row.user_name}}" class="js-user-password"> <a href="#" data-slug="{% endverbatim %}{{organisation.slug}}{% verbatim %}" data-user_name="{{row.user_name}}" class="js-member-password" aria-label="{% endverbatim %}{{translate("MEMBER.RESET_PASSWORD")}}{% verbatim %}: {{row.full_name}} ({{row.user_name}})">
<i class="fas fa-key"></i> {% endverbatim %}{{translate("MEMBER.CHANGE_PASSWORD")}}{% verbatim %} <i class="fas fa-key"></i> {% endverbatim %}{{translate("MEMBER.RESET_PASSWORD")}}{% verbatim %}
</a> </a>
</li> </li>
<li> <li role="menuitem">
<a href="#" data-slug="{% endverbatim %}{{organisation.slug}}{% verbatim %}" data-user_name="{{row.user_name}}" class="js-member-remove"> <a href="#" data-slug="{% endverbatim %}{{organisation.slug}}{% verbatim %}" data-user_name="{{row.user_name}}" class="js-member-remove" aria-label="{% endverbatim %}{{translate("MEMBER.REMOVE")}}{% verbatim %}: {{row.full_name}} ({{row.user_name}})">
<i class="fas fa-door-open"></i> {% endverbatim %}{{translate("MEMBER.REMOVE")}}{% verbatim %} <i class="fas fa-door-open"></i> {% endverbatim %}{{translate("MEMBER.REMOVE")}}{% verbatim %}
</a> </a>
</li> </li>

View File

@@ -12,7 +12,7 @@
</strong> </strong>
<div class="js-copy-container"> <div class="js-copy-container">
<span class="js-copy-target">{{row.email}}</span> <span class="js-copy-target">{{row.email}}</span>
<button class="btn btn-xs uf-copy-trigger js-copy-trigger"><i class="fas fa-copy"></i></button> <button class="btn btn-xs uf-copy-trigger js-copy-trigger" aria-label="Copy email address"><i class="fas fa-copy"></i></button>
</div> </div>
</td> </td>
{% endverbatim %} {% endverbatim %}

View File

@@ -17,7 +17,7 @@
{% block organisation_membership_actions %} {% block organisation_membership_actions %}
{% if organisationConfig.combine_action_buttons %} {% if organisationConfig.combine_action_buttons %}
{% verbatim %}{{#ifx row.is_pending '==' 1 }}{% endverbatim %} {% verbatim %}{{#ifx row.is_pending '==' 1 }}{% endverbatim %}
<li> <li role="menuitem">
<a href="#" data-slug="{% verbatim %}{{row.slug}}{% endverbatim %}" class="js-organisation-cancelJoin"> <a href="#" data-slug="{% verbatim %}{{row.slug}}{% endverbatim %}" class="js-organisation-cancelJoin">
<i class="fas fa-window-close"></i> <i class="fas fa-window-close"></i>
{{translate("JOIN.CANCEL")}} {{translate("JOIN.CANCEL")}}
@@ -25,7 +25,7 @@
</li> </li>
{% verbatim %}{{ else }}{% endverbatim %} {% verbatim %}{{ else }}{% endverbatim %}
{% verbatim %}{{#ifx row.is_member '==' 1 }}{% endverbatim %} {% verbatim %}{{#ifx row.is_member '==' 1 }}{% endverbatim %}
<li> <li role="menuitem">
<a href="#" data-slug="{% verbatim %}{{row.slug}}{% endverbatim %}" class="js-organisation-leave"> <a href="#" data-slug="{% verbatim %}{{row.slug}}{% endverbatim %}" class="js-organisation-leave">
<i class="fas fa-sign-out-alt"></i> <i class="fas fa-sign-out-alt"></i>
{{translate("LEAVE")}} {{translate("LEAVE")}}
@@ -33,7 +33,7 @@
</li> </li>
{% verbatim %}{{ else }}{% endverbatim %} {% verbatim %}{{ else }}{% endverbatim %}
{% if (organisationConfig.membership.single_membership == 0) or ((current_user.organisations.count == 0) and (current_user.pendingOrganisations.count == 0)) %} {% if (organisationConfig.membership.single_membership == 0) or ((current_user.organisations.count == 0) and (current_user.pendingOrganisations.count == 0)) %}
<li> <li role="menuitem">
<a href="#" data-slug="{% verbatim %}{{row.slug}}{% endverbatim %}" class="js-organisation-join"> <a href="#" data-slug="{% verbatim %}{{row.slug}}{% endverbatim %}" class="js-organisation-join">
<i class="fas fa-sign-in-alt"></i> <i class="fas fa-sign-in-alt"></i>
{{translate("JOIN")}} {{translate("JOIN")}}
@@ -63,7 +63,7 @@
{% verbatim %}{{#ifx row.is_admin '==' 1 }}{% endverbatim %} {% verbatim %}{{#ifx row.is_admin '==' 1 }}{% endverbatim %}
{% endif %} {% endif %}
{% endif %} {% endif %}
<li> <li role="menuitem">
<a href="#" data-slug="{% verbatim %}{{row.slug}}{% endverbatim %}" class="js-organisation-edit"> <a href="#" data-slug="{% verbatim %}{{row.slug}}{% endverbatim %}" class="js-organisation-edit">
<i class="fas fa-edit"></i> <i class="fas fa-edit"></i>
{{translate("ORGANISATION.EDIT")}} {{translate("ORGANISATION.EDIT")}}
@@ -78,7 +78,7 @@
{% if checkAccess('approve_organisation') %} {% if checkAccess('approve_organisation') %}
{% verbatim %}{{#ifx row.flag_approved '==' 0 }}{% endverbatim %} {% verbatim %}{{#ifx row.flag_approved '==' 0 }}{% endverbatim %}
{% verbatim %}{{#ifx row.registrant_id '==' {% endverbatim %}{{current_user.id}}{% verbatim %} }}{% endverbatim %} {% verbatim %}{{#ifx row.registrant_id '==' {% endverbatim %}{{current_user.id}}{% verbatim %} }}{% endverbatim %}
<li> <li role="menuitem">
<a href="#" data-slug="{% verbatim %}{{row.slug}}{% endverbatim %}" class="js-organisation-cancelRegistration"> <a href="#" data-slug="{% verbatim %}{{row.slug}}{% endverbatim %}" class="js-organisation-cancelRegistration">
<i class="fas fa-trash-alt"></i> <i class="fas fa-trash-alt"></i>
{{translate("ORGANISATION.REGISTRATION.CANCEL")}} {{translate("ORGANISATION.REGISTRATION.CANCEL")}}
@@ -86,12 +86,12 @@
</li> </li>
{% verbatim %}{{/ifx}}{% endverbatim %} {% verbatim %}{{/ifx}}{% endverbatim %}
<li> <li role="menuitem">
<a href="#" data-slug="{% verbatim %}{{row.slug}}{% endverbatim %}" class="js-organisation-approveRegistration"> <a href="#" data-slug="{% verbatim %}{{row.slug}}{% endverbatim %}" class="js-organisation-approveRegistration">
<i class="fas fa-thumbs-up"></i> {{translate("ORGANISATION.REGISTRATION.APPROVE")}} <i class="fas fa-thumbs-up"></i> {{translate("ORGANISATION.REGISTRATION.APPROVE")}}
</a> </a>
</li> </li>
<li> <li role="menuitem">
<a href="#" data-slug="{% verbatim %}{{row.slug}}{% endverbatim %}" class="js-organisation-denyRegistration"> <a href="#" data-slug="{% verbatim %}{{row.slug}}{% endverbatim %}" class="js-organisation-denyRegistration">
<i class="fas fa-thumbs-down"></i> <i class="fas fa-thumbs-down"></i>
{{translate("ORGANISATION.REGISTRATION.DENY")}} {{translate("ORGANISATION.REGISTRATION.DENY")}}
@@ -102,7 +102,7 @@
{% if checkAccess('merge_organisations') %} {% if checkAccess('merge_organisations') %}
<li> <li role="menuitem">
<a href="#" data-slug="{% verbatim %}{{row.slug}}{% endverbatim %}" class="js-organisation-merge"> <a href="#" data-slug="{% verbatim %}{{row.slug}}{% endverbatim %}" class="js-organisation-merge">
<i class="fas fa-object-group"></i> <i class="fas fa-object-group"></i>
{{translate("ORGANISATION.MERGE")}} {{translate("ORGANISATION.MERGE")}}
@@ -112,7 +112,7 @@
{% if checkAccess('delete_organisation') %} {% if checkAccess('delete_organisation') %}
{% verbatim %}{{#ifx row.flag_approved '==' 1 }}{% endverbatim %} {% verbatim %}{{#ifx row.flag_approved '==' 1 }}{% endverbatim %}
<li> <li role="menuitem">
<a href="#" data-slug="{% verbatim %}{{row.slug}}{% endverbatim %}" class="js-organisation-delete"> <a href="#" data-slug="{% verbatim %}{{row.slug}}{% endverbatim %}" class="js-organisation-delete">
<i class="fas fa-trash-alt"></i> <i class="fas fa-trash-alt"></i>
{{translate("ORGANISATION.DELETE")}} {{translate("ORGANISATION.DELETE")}}

View File

@@ -10,12 +10,12 @@
</button> </button>
{{ else }} {{ else }}
{{#ifx row.is_member '==' 1 }} {{#ifx row.is_member '==' 1 }}
<button type="button" data-slug="{{row.slug}}" class="btn btn-danger js-organisation-leave" style="min-width: 70px"> <button type="button" data-slug="{{row.slug}}" class="btn btn-danger js-organisation-leave" style="min-width: 70px" title="{% endverbatim %}{{translate("LEAVE")}}{% verbatim %} {{row.name}}" aria-label="{% endverbatim %}{{translate("LEAVE")}}{% verbatim %} {{row.name}}">
{% endverbatim %}{{translate("LEAVE")}}{% verbatim %} {% endverbatim %}{{translate("LEAVE")}}{% verbatim %}
</button> </button>
{{ else }} {{ else }}
{% endverbatim %}{% if (organisationConfig.membership.single_membership == 0) or ((current_user.organisations.count == 0) and (current_user.pendingOrganisations.count == 0)) %}{% verbatim %} {% endverbatim %}{% if (organisationConfig.membership.single_membership == 0) or ((current_user.organisations.count == 0) and (current_user.pendingOrganisations.count == 0)) %}{% verbatim %}
<button type="button" data-slug="{{row.slug}}" class="btn btn-success js-organisation-join" style="min-width: 70px"> <button type="button" data-slug="{{row.slug}}" class="btn btn-success js-organisation-join" style="min-width: 70px" title="{% endverbatim %}{{translate("JOIN")}}{% verbatim %} {{row.name}}" aria-label="{% endverbatim %}{{translate("JOIN")}}{% verbatim %} {{row.name}}">
{% endverbatim %}{{translate("JOIN")}}{% verbatim %} {% endverbatim %}{{translate("JOIN")}}{% verbatim %}
</button> </button>
{% endverbatim %}{% endif %}{% verbatim %} {% endverbatim %}{% endif %}{% verbatim %}

View File

@@ -5,33 +5,33 @@
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown">{% endverbatim %}{{translate("ACTIONS")}}{% verbatim %}<span class="caret"></span></button> <button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown">{% endverbatim %}{{translate("ACTIONS")}}{% verbatim %}<span class="caret"></span></button>
<ul class="dropdown-menu dropdown-menu-right-responsive" role="menu"> <ul class="dropdown-menu dropdown-menu-right-responsive" role="menu">
{{#ifx row.flag_verified '==' 0 }} {{#ifx row.flag_verified '==' 0 }}
<li> <li role="menuitem">
<a href="#" data-user_name="{{row.user_name}}" class="js-user-activate"> <a href="#" data-user_name="{{row.user_name}}" class="js-user-activate">
<i class="fas fa-bolt"></i> {% endverbatim %}{{translate("USER.ACTIVATE")}}{% verbatim %} <i class="fas fa-bolt"></i> {% endverbatim %}{{translate("USER.ACTIVATE")}}{% verbatim %}
</a> </a>
</li> </li>
{{/ifx }} {{/ifx }}
<li> <li role="menuitem">
<a href="#" data-user_name="{{row.user_name}}" class="js-user-edit"> <a href="#" data-user_name="{{row.user_name}}" class="js-user-edit">
<i class="fas fa-edit"></i> {% endverbatim %}{{translate("USER.EDIT")}}{% verbatim %} <i class="fas fa-edit"></i> {% endverbatim %}{{translate("USER.EDIT")}}{% verbatim %}
</a> </a>
</li> </li>
<li> <li role="menuitem">
<a href="#" data-user_name="{{row.user_name}}" class="js-user-roles"> <a href="#" data-user_name="{{row.user_name}}" class="js-user-roles">
<i class="fas fa-id-card"></i> {% endverbatim %}{{translate("ROLE.MANAGE")}}{% verbatim %} <i class="fas fa-id-card"></i> {% endverbatim %}{{translate("ROLE.MANAGE")}}{% verbatim %}
</a> </a>
</li> </li>
<li> <li role="menuitem">
<a href="#" data-user_name="{{row.user_name}}" class="js-user-organisations"> <a href="#" data-user_name="{{row.user_name}}" class="js-user-organisations">
<i class="fas fa-sitemap"></i> {% endverbatim %}{{translate("ORGANISATION.MANAGE")}}{% verbatim %} <i class="fas fa-sitemap"></i> {% endverbatim %}{{translate("ORGANISATION.MANAGE")}}{% verbatim %}
</a> </a>
</li> </li>
<li> <li role="menuitem">
<a href="#" data-user_name="{{row.user_name}}" class="js-user-password"> <a href="#" data-user_name="{{row.user_name}}" class="js-user-password">
<i class="fas fa-key"></i> {% endverbatim %}{{translate("USER.ADMIN.CHANGE_PASSWORD")}}{% verbatim %} <i class="fas fa-key"></i> {% endverbatim %}{{translate("USER.ADMIN.CHANGE_PASSWORD")}}{% verbatim %}
</a> </a>
</li> </li>
<li> <li role="menuitem">
{{#ifx row.flag_enabled '==' 1 }} {{#ifx row.flag_enabled '==' 1 }}
<a href="#" data-user_name="{{row.user_name}}" class="js-user-disable"> <a href="#" data-user_name="{{row.user_name}}" class="js-user-disable">
<i class="fas fa-minus-circle"></i> {% endverbatim %}{{translate("USER.DISABLE")}}{% verbatim %} <i class="fas fa-minus-circle"></i> {% endverbatim %}{{translate("USER.DISABLE")}}{% verbatim %}
@@ -42,7 +42,7 @@
</a> </a>
{{/ifx }} {{/ifx }}
</li> </li>
<li> <li role="menuitem">
<a href="#" data-user_name="{{row.user_name}}" class="js-user-delete"> <a href="#" data-user_name="{{row.user_name}}" class="js-user-delete">
<i class="fas fa-trash-alt"></i> {% endverbatim %}{{translate("USER.DELETE")}}{% verbatim %} <i class="fas fa-trash-alt"></i> {% endverbatim %}{{translate("USER.DELETE")}}{% verbatim %}
</a> </a>

View File

@@ -3,12 +3,12 @@
<td style="line-height: 2em;"> <td style="line-height: 2em;">
{{#if row.organisations.length }} {{#if row.organisations.length }}
{{#each row.organisations }} {{#each row.organisations }}
<a href="{% endverbatim %}{{site.uri.public}}{% verbatim %}/organisations/o/{{this.slug}}" class="label bg-primary {{#ifx this.flag_approved '!=' 1 }}organisation-pending{{/ifx}} {{#if this.pivot.flag_admin }}organisation-admin{{/if}}" title="{{this.description}}" data-text="{{this.name}}" style="font-size: 100%;">{{this.name}}</a><br> <a href="{% endverbatim %}{{site.uri.public}}{% verbatim %}/organisations/o/{{this.slug}}" class="label bg-primary user-organisation-button {{#ifx this.flag_approved '!=' 1 }}organisation-pending{{/ifx}} {{#if this.pivot.flag_admin }}organisation-admin{{/if}}" title="{{this.description}}" data-text="{{this.name}}">{{this.name}}</a><br>
{{/each}} {{/each}}
{{/if }} {{/if }}
{{#if row.pending_organisations.length }} {{#if row.pending_organisations.length }}
{{#each row.pending_organisations }} {{#each row.pending_organisations }}
<a href="{% endverbatim %}{{site.uri.public}}{% verbatim %}/organisations/o/{{this.slug}}" class="label bg-primary {{#ifx this.flag_approved '!=' 1 }}organisation-pending{{/ifx}} {{#if this.pivot.flag_admin }}organisation-admin{{/if}} membership-pending" title="{{this.description}}" data-text="{{this.name}}" style="font-size: 100%;">{{this.name}}</a><br> <a href="{% endverbatim %}{{site.uri.public}}{% verbatim %}/organisations/o/{{this.slug}}" class="label bg-primary user-organisation-button {{#ifx this.flag_approved '!=' 1 }}organisation-pending{{/ifx}} {{#if this.pivot.flag_admin }}organisation-admin{{/if}} membership-pending" title="{{this.description}}" data-text="{{this.name}}">{{this.name}}</a><br>
{{/each}} {{/each}}
{{/if }} {{/if }}
</td> </td>