Setup enrolments in Moodle 2.x - moodle

An Enrol Plugin in Moodle 1.9x could have a setup_enrolments(&$user) method to set user enrolments. This method was called by the lib when user log in.
Does Moodle 2.x uses a similar method?
I couldn't find any call to setup_enrolments() method. Must it have another name?

Yes, I believe enrol_plugin::sync_user_enrolments() does it. From lib/enrollib.php:
/**
* Forces synchronisation of user enrolments.
*
* This is important especially for external enrol plugins,
* this function is called for all enabled enrol plugins
* right after every user login.
*
* #param object $user user record
* #return void
*/
public function sync_user_enrolments($user) {
// override if necessary
}

Related

In Backpack, where is the appropriate place to put the authorize() call?

Backpack controllers do not contain Rest methods as is typical with Laravel, but use traits to implement CRUD operations, and occasionally (but not always - delete does not for example) setup methods (setupListOperation for example).
For authorization, for the rest of my app I use Gate declarations in AppServiceProvider, and declare $this->authorize() to check authorization in each of my controllers.
Where can I use authorize() to check each of the operations I implement from Backpack? I couldn't find a method that seemed appropriate to override in order to run that authorization before proceeding.
You will normally do this in your FormRequest classes, see https://backpackforlaravel.com/docs/4.1/crud-tutorial#the-request
Example:
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
use Illuminate\Foundation\Http\FormRequest;
class TagRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return backpack_auth()->check();
}
}
Then you'd set the request as a validator for the given opperation:
Example
protected function setupCreateOperation()
{
$this->crud->setValidation(TagRequest::class);
// TODO: remove setFromDb() and manually define Fields
$this->crud->setFromDb();
}
NOTE: While its not clear in the documentation or generated controllers (if you use the command line generator) you can in fact set a setup method for ALL opperations:
If you look at the packages allin.com/vendor/backpack/crud/src/app/Http/Controllers/CrudController.php file, in the setupConfigurationForCurrentOperation method you'll find:
/**
* Load configurations for the current operation.
*
* Allow developers to insert default settings by creating a method
* that looks like setupOperationNameOperation (aka setupXxxOperation).
*/
protected function setupConfigurationForCurrentOperation()
{
$operationName = $this->crud->getCurrentOperation();
$setupClassName = 'setup'.Str::studly($operationName).'Operation';
//.....
/*
* THEN, run the corresponding setupXxxOperation if it exists.
*/
if (method_exists($this, $setupClassName)) {
$this->{$setupClassName}();
}
}
This means that if your controller defines a setupDeleteOperation function, it WILL be called during the setup of the delete route for your CRUD.
After making use of #Wesley Smith's answer, I discovered a one-step approach to this.
As Wesley mentions, you can create setup methods for all of the crud operations, and this works as an excellent place to pass an auth. However, it does not update the other operation's links. For example, list will still contain a link to "edit," even if it's unauthorized. You can remove these with individual lines, but there's an easier way.
Instead, you can use the Setup method to pass allow/deny methods. Here's what my setup() now appears as.
public function setup()
{
CRUD::setModel(Workshop::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/workshop');
CRUD::setEntityNameStrings('workshop', 'workshops');
if (Gate::denies('admin.workshop.list'))
$this->crud->denyAccess('list');
if (Gate::denies('admin.workshop.show'))
$this->crud->denyAccess('show');
if (Gate::denies('admin.workshop.create'))
$this->crud->denyAccess('create');
if (Gate::denies('admin.workshop.update'))
$this->crud->denyAccess('update');
if (Gate::denies('admin.workshop.delete'))
$this->crud->denyAccess('delete');
}
This will not only deny access to the methods, but update each method with the appropriate #can blade directives, meaning unauthorized methods won't appear as links.

How to generate a rating meta tag in TYPO3 with caching?

I would like to generate a rich snippet for ratings in my TYPO3 pages. The rating information are fetched via an API, so I need some kind of caching mechanism.
I have some basic knowledge and experience with TYPO3 extensions, but I am not sure about the cleanest solution. I could render the meta tags with the TYPO3 Meta Tag API and cache the fetched information using the TYPO3 Caching Framework.
But I am not sure where to store the logic so that it gets executed at every page visit. I do not want to use a content plugin for obvious reasons. Should I set up a Controller and call the Contoller's function with e.g. some hook?
Thanks for any help!
You may have a look at the tslib/class.tslib_fe.php hooks in TypoScriptFrontendController class.
Choose the correct one (maybe tslib_fe-PostProc) and do something like this :
1) Register hook in ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-PostProc'][] = \Vendor\Name\Hook\AdditionalMetaData::class . '->addRating';
2) Create your class with the following method
<?php
namespace Vendor\Name\Hook;
class AdditionalMetaData
{
/**
* #param array $parameters
* #return void
*/
public function addRating(&$parameters)
{
/** #var TypoScriptFrontendController $tsfe */
$tsfe = &$parameters['pObj'];
// Do your logic here...
}
}

Cannot restrict access to permission manager routes using role-based middleware

PHP 7.3
Laravel 5.8
Laravel Backpack 3.6
I am trying to use the middlware 'role:admin' within my routes/backpack/permissionmanager.php file, to restrict access to the User, Roles and Permissions areas of Backpack to a subset of users with certain roles.
I have made sure that my User account has been granted the correct role.
My 'user' model in config/backpack/permissionmanager.php is set to App\User::class and my User model has and uses the necessary traits as outlined in the documentation.
I have placed a role Middleware into my app, as follows:
<?php
namespace App\Http\Middleware;
use Closure;
class RoleMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next, $role)
{
if (backpack_auth()->guest()) {
return redirect('login');
}
if (! backpack_user()->hasRole($role)) {
abort(403);
}
return $next($request);
}
}
However, it seems that this middleware's backpack_user(), while knowing who I am through the correct return of the ->name property, has absolutely no idea of the roles or permissions that I am supposed to have assigned to myself. I have checked this using the ->getRoleNames() method and it returns an empty collection.
Within the database, the correct entries and IDs are set within the model_has_roles table for my User account and the Role I want.
However, navigating to myapp.dev/admin/user results in a 403 Forbidden.
I think this might be a bug, or something I must not be seeing correctly...?

Why is redirect resetting my object?

I made a frontend extension with Extbase in TYPO3 6.2 and while redirecting in my controller I'm loosing changes I've made to my object.
I wonder if this is intended and why?
Here I see the change I've made to appointment in the var_dump.
/**
*
* #param Domain\Model\Appointment $appointment
* #return void
*/
public function bookAction(Domain\Model\Appointment $appointment) {
if ($appointment->getBooked()) {
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($appointment);
$this->redirect('update', null, null, array('appointment'=>$appointment));
}
}
Then I see the original object before the changes I've made to appointment in the var_dump.
It seems like the passing of the changed appointment resets it back to its original state...?
/**
* action update
*
* #param Domain\Model\Appointment $appointment
* #return void
*/
public function updateAction(Domain\Model\Appointment $appointment) {
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($appointment);
}
Extbase controllers contain two methods of calling different action within your current action: redirect() and forward().
The difference is tiny, but consequences can be huge.
redirect() calls a different action via 30x HTTP redirect, so basically it requires complete page reload with restoring (and re-initializing) PHP session, data and objects.
Internally Extbase passes just an object's id to a second action, meaning, that in that second action your object is fetched from persistence again. And if the changes were not persisted in previous action, they'll be lost.
forward() just terminates the current MVC request and starts a new one without a page reload, meaning that all the session data and not-peristed changes are still available in a second action.
In this case Extbase passes not an id, but real object, so the changes are still there.
You can do one of the following:
Use forward() instead of redirect().
Persist changes to db via PersistenceManager before calling redirect().
Preserve your object changes somehow (e.g. pass not a real instance to redirect(), but serialized string and then unserialize it in your second action).
I don't see any code where you actually persist anything. So you need that in your update action
$persistenceManager = $this->objectManager->get("TYPO3\\CMS\\Extbase\\Persistence\\Generic\\PersistenceManager");
$persistenceManager->persistAll();
Just changing the object without persisting it won't change anything!

Multiple instances of Zend_Auth

I want to create multiple instances of Zend_Auth class as I have two modules
Admin
Front
What's happening is when I login into Admin, it automatically get logged into
Front or vice-versa.
What I want is to work in both modules separately after simultaneous authentication.
Zend_Auth is a singleton, so you can't. What I do is to use Zend_Acl ensure that only users with a role of "admin" can get at the administration stuff.
To create a second Auth object, in principle, you could derive Zend_Auth to App_Auth and use a different session namespace. I've never tried this, but my starting code would look like this:
class App_Auth
{
/**
* Returns the persistent storage handler
*
* Session storage is used by default unless a different storage adapter has been set.
*
* #return Zend_Auth_Storage_Interface
*/
public function getStorage()
{
if (null === $this->_storage) {
/**
* #see Zend_Auth_Storage_Session
*/
require_once 'Zend/Auth/Storage/Session.php';
$this->setStorage(new Zend_Auth_Storage_Session('App_Auth'));
}
return $this->_storage;
}
}
It's possible that you have to override more.