Allow users to see their own organisation pages
This commit is contained in:
@@ -1,5 +1,20 @@
|
|||||||
{
|
{
|
||||||
"bundle": {
|
"bundle": {
|
||||||
|
"js/admin": {
|
||||||
|
"scripts": [
|
||||||
|
"vendor/moment/moment.js",
|
||||||
|
"userfrosting/js/handlebars-helpers.js",
|
||||||
|
"vendor/tablesorter/dist/js/jquery.tablesorter.js",
|
||||||
|
"vendor/tablesorter/dist/js/jquery.tablesorter.widgets.js",
|
||||||
|
"userfrosting/js/tablesorter/widget-sort2Hash.js",
|
||||||
|
"vendor/tablesorter/dist/js/widgets/widget-columnSelector.min.js",
|
||||||
|
"vendor/tablesorter/dist/js/widgets/widget-reflow.min.js",
|
||||||
|
"vendor/tablesorter/dist/js/widgets/widget-pager.min.js",
|
||||||
|
"userfrosting/js/query-string.js",
|
||||||
|
"userfrosting/js/uf-table.js",
|
||||||
|
"avsdev/js/sidebar.js"
|
||||||
|
]
|
||||||
|
},
|
||||||
"js/pages/organisation": {
|
"js/pages/organisation": {
|
||||||
"scripts": [
|
"scripts": [
|
||||||
"userfrosting/js/widgets/users.js",
|
"userfrosting/js/widgets/users.js",
|
||||||
|
|||||||
23
assets/avsdev/js/sidebar.js
Normal file
23
assets/avsdev/js/sidebar.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
|
$('.sidebar-menu .collapse, .sidebar-menu .collapsing').on('hide.bs.collapse', function() {
|
||||||
|
$(this).prev().find('.fa').eq(1).removeClass('fa-angle-right').addClass('fa-angle-down');
|
||||||
|
var states = JSON.parse(localStorage.getItem('sidebar-states') || {});
|
||||||
|
states[this.id] = 0;
|
||||||
|
localStorage.setItem('sidebar-states', JSON.stringify(states));
|
||||||
|
});
|
||||||
|
$('.sidebar-menu .collapse, sidebar-menu .collapsing').on('show.bs.collapse', function() {
|
||||||
|
$(this).prev().find('.fa').eq(1).removeClass('fa-angle-down').addClass('fa-angle-right');
|
||||||
|
var states = JSON.parse(localStorage.getItem('sidebar-states') || {});
|
||||||
|
states[this.id] = 1;
|
||||||
|
localStorage.setItem('sidebar-states', JSON.stringify(states));
|
||||||
|
});
|
||||||
|
|
||||||
|
var states = JSON.parse(localStorage.getItem('sidebar-states') || {});
|
||||||
|
Object.getOwnPropertyNames(states).forEach((elid) => {
|
||||||
|
if (states[elid] === 1) {
|
||||||
|
$('#' + elid).collapse('show');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
@@ -36,9 +36,11 @@ 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 <sub>(excl admins)</sub>',
|
||||||
'ADMIN_COUNT' => '# Admins',
|
'ADMIN_COUNT' => '# Admins',
|
||||||
|
|
||||||
|
'SELF' => 'My Organisations',
|
||||||
|
|
||||||
'NAME' => [
|
'NAME' => [
|
||||||
1 => 'Organisation name',
|
1 => 'Organisation name',
|
||||||
|
|
||||||
|
|||||||
@@ -74,10 +74,7 @@ class OrganisationMembersController extends SimpleController
|
|||||||
|
|
||||||
$sprunje = $classMapper->createInstance('user_sprunje', $classMapper, $params);
|
$sprunje = $classMapper->createInstance('user_sprunje', $classMapper, $params);
|
||||||
$sprunje->extendQuery(function ($query) use ($classMapper, $organisation) {
|
$sprunje->extendQuery(function ($query) use ($classMapper, $organisation) {
|
||||||
return $query
|
return $query->where('organisation_id', $organisation->id);
|
||||||
->join('organisation_members', function($join) use($organisation) {
|
|
||||||
$join->on('organisation_members.user_id', '=', 'users.id')->where('organisation_id', $organisation->id);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Be careful how you consume this data - it has not been escaped and contains untrusted user-supplied content.
|
// Be careful how you consume this data - it has not been escaped and contains untrusted user-supplied content.
|
||||||
|
|||||||
76
src/Database/Models/User.php
Normal file
76
src/Database/Models/User.php
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AVSDev UF Organisations (https://avsdev.uk)
|
||||||
|
*
|
||||||
|
* @link https://git.avsdev.uk/avsdev/sprinkle-organisations
|
||||||
|
* @license https://git.avsdev.uk/avsdev/sprinkle-organisations/blob/master/LICENSE.md (LGPL-3.0 License)
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace UserFrosting\Sprinkle\Organisations\Database\Models;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
use UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface;
|
||||||
|
use UserFrosting\Sprinkle\Account\Database\Models\User as UFUser;
|
||||||
|
use UserFrosting\Sprinkle\Account\Facades\Password;
|
||||||
|
use UserFrosting\Sprinkle\Core\Database\Models\Model;
|
||||||
|
use UserFrosting\Sprinkle\Core\Facades\Debug;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User Class.
|
||||||
|
*
|
||||||
|
* Extends the UF User object by adding organisation membership
|
||||||
|
*
|
||||||
|
* @author Craig Williams (https://avsdev.uk)
|
||||||
|
*/
|
||||||
|
class User extends UFUser
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get all organisations this user is a member of.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||||
|
*/
|
||||||
|
public function organisations()
|
||||||
|
{
|
||||||
|
/** @var \UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */
|
||||||
|
$classMapper = static::$ci->classMapper;
|
||||||
|
|
||||||
|
return $this->belongsToMany($classMapper->getClassMapping('organisation'), 'organisation_members', 'user_id', 'organisation_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete this member from the database, along with any links to organisations.
|
||||||
|
*
|
||||||
|
* @param bool $hardDelete Set to true to completely remove the member and all associated objects.
|
||||||
|
*
|
||||||
|
* @return bool true if the deletion was successful, false otherwise.
|
||||||
|
*/
|
||||||
|
public function delete($hardDelete = false)
|
||||||
|
{
|
||||||
|
/** @var \UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */
|
||||||
|
$classMapper = static::$ci->classMapper;
|
||||||
|
|
||||||
|
if ($hardDelete) {
|
||||||
|
// TODO: remove user from organisations?
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Joins the user's organisations directly, so we can do things like sort, search, paginate, etc.
|
||||||
|
*
|
||||||
|
* @param Builder $query
|
||||||
|
*
|
||||||
|
* @return Builder
|
||||||
|
*/
|
||||||
|
public function scopeJoinOrganisations($query)
|
||||||
|
{
|
||||||
|
$query = $query->leftJoin('organisation_members', 'organisation_members.user_id', '=', 'users.id');
|
||||||
|
$query = $query->leftJoin('organisations', 'organisations.id', '=', 'organisation_members.organisation_id');
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ class OrganisationPermissions extends BaseSeed
|
|||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
// We require the default roles
|
// We require the default roles
|
||||||
|
Seeder::execute('DefaultPermissions');
|
||||||
Seeder::execute('DefaultRoles');
|
Seeder::execute('DefaultRoles');
|
||||||
Seeder::execute('OrganisationRoles');
|
Seeder::execute('OrganisationRoles');
|
||||||
|
|
||||||
@@ -56,6 +57,12 @@ class OrganisationPermissions extends BaseSeed
|
|||||||
'conditions' => "in(property,['name','slug','description','members'])",
|
'conditions' => "in(property,['name','slug','description','members'])",
|
||||||
'description' => 'View certain properties of any organisation.',
|
'description' => 'View certain properties of any organisation.',
|
||||||
]),
|
]),
|
||||||
|
'view_organisation_field_own' => new Permission([
|
||||||
|
'slug' => 'view_organisation_field',
|
||||||
|
'name' => 'View own organisation',
|
||||||
|
'conditions' => "is_organisation_member(self.id,organisation.id) & in(property,['name','slug','description','members'])",
|
||||||
|
'description' => 'View certain properties of own organisation.',
|
||||||
|
]),
|
||||||
'update_organisation_field' => new Permission([
|
'update_organisation_field' => new Permission([
|
||||||
'slug' => 'update_organisation_field',
|
'slug' => 'update_organisation_field',
|
||||||
'name' => 'Edit organisation',
|
'name' => 'Edit organisation',
|
||||||
@@ -80,6 +87,12 @@ class OrganisationPermissions extends BaseSeed
|
|||||||
'conditions' => 'always()',
|
'conditions' => 'always()',
|
||||||
'description' => 'View the organisation page of any organisation.',
|
'description' => 'View the organisation page of any organisation.',
|
||||||
]),
|
]),
|
||||||
|
'uri_organisation_own' => new Permission([
|
||||||
|
'slug' => 'uri_organisation',
|
||||||
|
'name' => 'View own organisation',
|
||||||
|
'conditions' => 'is_organisation_member(self.id,organisation.id)',
|
||||||
|
'description' => 'View the organisation page of an organisation you are a member of.',
|
||||||
|
]),
|
||||||
'uri_organisations' => new Permission([
|
'uri_organisations' => new Permission([
|
||||||
'slug' => 'uri_organisations',
|
'slug' => 'uri_organisations',
|
||||||
'name' => 'Organisation management page',
|
'name' => 'Organisation management page',
|
||||||
@@ -144,6 +157,13 @@ class OrganisationPermissions extends BaseSeed
|
|||||||
$permissions['uri_organisation']->id,
|
$permissions['uri_organisation']->id,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$roleUser = Role::where('slug', 'user')->first();
|
||||||
|
if ($roleUser) {
|
||||||
|
$roleUser->permissions()->syncWithoutDetaching([
|
||||||
|
$permissions['uri_organisation_own']->id,
|
||||||
|
$permissions['view_organisation_field_own']->id,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
namespace UserFrosting\Sprinkle\Organisations\ServicesProvider;
|
namespace UserFrosting\Sprinkle\Organisations\ServicesProvider;
|
||||||
|
|
||||||
|
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||||
use Psr\Container\ContainerInterface;
|
use Psr\Container\ContainerInterface;
|
||||||
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;
|
||||||
@@ -38,10 +39,49 @@ class ServicesProvider
|
|||||||
$container->extend('classMapper', function ($classMapper, $c) {
|
$container->extend('classMapper', function ($classMapper, $c) {
|
||||||
$classMapper->setClassMapping('organisation', 'UserFrosting\Sprinkle\Organisations\Database\Models\Organisation');
|
$classMapper->setClassMapping('organisation', 'UserFrosting\Sprinkle\Organisations\Database\Models\Organisation');
|
||||||
$classMapper->setClassMapping('organisation_sprunje', 'UserFrosting\Sprinkle\Organisations\Sprunje\OrganisationSprunje');
|
$classMapper->setClassMapping('organisation_sprunje', 'UserFrosting\Sprinkle\Organisations\Sprunje\OrganisationSprunje');
|
||||||
|
$classMapper->setClassMapping('user', 'UserFrosting\Sprinkle\Organisations\Database\Models\User');
|
||||||
|
$classMapper->setClassMapping('user_sprunje', 'UserFrosting\Sprinkle\Organisations\Sprunje\UserSprunje');
|
||||||
|
|
||||||
return $classMapper;
|
return $classMapper;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extend the 'authorizer' service to add extra access condition callbacks.
|
||||||
|
*
|
||||||
|
* @return \UserFrosting\Sprinkle\Core\Util\ClassMapper
|
||||||
|
*/
|
||||||
|
$container->extend('authorizer', function ($authorizer, $c) {
|
||||||
|
/*
|
||||||
|
* Check if all $user is a member of $organisation.
|
||||||
|
*
|
||||||
|
* @param int $user_id the id of the requesting user (normally currentUser->id).
|
||||||
|
* @param int $organisation_id the id of the target organisation.
|
||||||
|
* @return bool true if $user is a member of $organisation.
|
||||||
|
*/
|
||||||
|
$authorizer->addCallback('is_organisation_member', function ($user_id, $organisation_id) {
|
||||||
|
return Capsule::table('organisation_members')
|
||||||
|
->where('user_id', $user_id)
|
||||||
|
->where('organisation_id', $organisation_id)
|
||||||
|
->count() > 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if all $user is an administrator of $organisation.
|
||||||
|
*
|
||||||
|
* @param int $user_id the id of the requesting user (normally currentUser->id).
|
||||||
|
* @param int $organisation_id the id of the target organisation.
|
||||||
|
* @return bool true if $user is an administrator of $organisation.
|
||||||
|
*/
|
||||||
|
$authorizer->addCallback('is_organisation_admin', function ($user_id, $organisation_id) {
|
||||||
|
return Capsule::table('organisation_members')
|
||||||
|
->where('user_id', $user_id)
|
||||||
|
->where('organisation_id', $organisation_id)
|
||||||
|
->where('flag_admin', true)
|
||||||
|
->count() > 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
return $authorizer;
|
||||||
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns a callback that handles merging any organisation objects.
|
* Returns a callback that handles merging any organisation objects.
|
||||||
@@ -79,6 +119,5 @@ class ServicesProvider
|
|||||||
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
85
src/Sprunje/UserSprunje.php
Normal file
85
src/Sprunje/UserSprunje.php
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AVSDev UF Organisations (https://avsdev.uk)
|
||||||
|
*
|
||||||
|
* @link https://git.avsdev.uk/avsdev/sprinkle-organisations
|
||||||
|
* @license https://git.avsdev.uk/avsdev/sprinkle-organisations/blob/master/LICENSE.md (LGPL-3.0 License)
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace UserFrosting\Sprinkle\Organisations\Sprunje;
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Builder;
|
||||||
|
use UserFrosting\Sprinkle\Core\Facades\Translator;
|
||||||
|
use UserFrosting\Sprinkle\Core\Sprunje\Sprunje;
|
||||||
|
use UserFrosting\Sprinkle\Admin\Sprunje\UserSprunje as UFUserSprunje;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UserSprunje.
|
||||||
|
*
|
||||||
|
* Extends Sprunje for the users API.
|
||||||
|
*
|
||||||
|
* @author Craig Williams (https://avsdev.uk)
|
||||||
|
*/
|
||||||
|
class UserSprunje extends UFUserSprunje
|
||||||
|
{
|
||||||
|
protected $filterable = [
|
||||||
|
'name',
|
||||||
|
'organisations',
|
||||||
|
'last_activity',
|
||||||
|
'status',
|
||||||
|
];
|
||||||
|
protected $sortable = [
|
||||||
|
'name',
|
||||||
|
'organisations',
|
||||||
|
'last_activity',
|
||||||
|
'status',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function baseQuery()
|
||||||
|
{
|
||||||
|
$query = parent::baseQuery();
|
||||||
|
|
||||||
|
// Join user's organisations
|
||||||
|
return $query->joinOrganisations()->with('organisations');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort based on organisations names.
|
||||||
|
*
|
||||||
|
* @param Builder $query
|
||||||
|
* @param mixed $value
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
protected function sortOrganisations($query, $direction)
|
||||||
|
{
|
||||||
|
$query->orderBy('organisations.name', $direction);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter LIKE the last activity description.
|
||||||
|
*
|
||||||
|
* @param Builder $query
|
||||||
|
* @param mixed $value
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
protected function filterOrganisations($query, $value)
|
||||||
|
{
|
||||||
|
// Split value on separator for OR queries
|
||||||
|
$values = explode($this->orSeparator, $value);
|
||||||
|
$query->where(function ($query) use ($values) {
|
||||||
|
foreach ($values as $value) {
|
||||||
|
$query->orLike('organisations.name', $value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,4 +40,16 @@
|
|||||||
<a href="{{site.uri.public}}/organisations"><i class="fas fa-users fa-fw"></i> <span>{{ translate("ORGANISATION", 2) }}</span></a>
|
<a href="{{site.uri.public}}/organisations"><i class="fas fa-users fa-fw"></i> <span>{{ translate("ORGANISATION", 2) }}</span></a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if current_user.organisations.count() > 0 %}
|
||||||
|
<li>
|
||||||
|
<a href="#" data-toggle="collapse" data-target="#submenu-organisations" class="" aria-expanded="false"><i class="fa fa-fw fa-users"></i> {{ translate("ORGANISATION.SELF") }} <i class="fa fa-fw pull-right fa-angle-down"></i></a>
|
||||||
|
<ul id="submenu-organisations" class="collapsable collapse" aria-expanded="false" style="height: 1px;">
|
||||||
|
{% for organisation in current_user.organisations %}
|
||||||
|
<li>
|
||||||
|
<a href="{{site.uri.public}}/organisations/o/{{organisation.slug}}"><i class="fas fa-angle-double-right"></i> <span>{{organisation.name}}</span></a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user