Restricting a resource in Moodle - moodle

I am trying to create access restrictions to a folder or resource inside of a section in a Moodle course using a Script. This restriction must be for groups of users and if you don't belong to that group you can not see the existing resources.
The operation programmatically I want to do is as follows:
I searched for information and there is very little documentation, in the documentation only puts how to do just that by the web link.
I know how to create groups, folders and sections programmatically from script, but I can not identify the tables to be used for these restrictions or what are the steps to follow.
So if anyone knows how to do it or have any examples or documentation that may be useful, it would be helpful.
Thanks in advance.

The classes which will be used to create the UI and check whether a user has access to your resource are located at:
availability/condition/group/classes/condition.php
availability/condition/group/classes/frontend.php
The data related to the conditions are formatted to JSON from the UI in Javascript, then sent and saved. My first guess would be that you need to recreate the JSON structure and save it into the table/column course_modules::availability. Once that is done I think you'll have to purge the cache from cm_info where the availability data is used to confirm whether the current user can access your resource.
update_moduleinfo - Saves the module form submitted data
cm_info - Checks whether the conditions are met

I followed your advice #FMC and I have done this function to my script that is responsible for giving permits to a group for a particular section of a course
and this is the code:
/**
* giving permits to a group for a particular section of a course
*
* #param $course course that contains the section to restrict access
* #param $sectionid id of the section to restrict access
* #param $groupid id of the group will have access
* #param $module id of the mdl_module to restrict access
*
*/
function grantPermission($course, $sectionid, $groupid, $module ){
global $DB;
$restriction = '{"op":"&","c":[{"type":"group","id":'. $groupid .'}],"showc":[true]}';
$cm= $DB->get_record('course_modules', array('course' => $course , 'section' => $sectionid, 'module' => $module ), '*', MUST_EXIST);
$course_module = new stdClass();
$course_module->id = $cm->id;
$course_module->course = $course;
$course_module->section = $sectionid;
$course_module->availability = $restriction;
$res = $DB->update_record('course_modules', $course_module);
if($res)
rebuild_course_cache($course, true);
return $res;
}
Can you check if is this what you meant #FMC? It works but I don't know if this is the best way.
Thank you!

Related

Backend access rights for news records

Is it possible to store all records of the news extension (ext:news) on the same storage page, but show only records, which are created by the loggedin backend user?
So the current backend user can just see and edit his own records? Admins should see all records of course.
No, this is not possible, since backend user permissions on record level are not implemented in TYPO3.
So you either have to separate the news records of the users in separate sysfolders or you could try to use hooks (e.g. $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['getTable']) or XClass to customize TYPO3 backend to your needs. I do not recommend the latter, since the TYPO3 backend permission system is complex and you would need to make sure to restrict record access in several parts of TYPO3 (e.g. recordlist, element browser, related news field, ...)
There are two ways to archive that:
If the backend user is not too much. You can just create a page(type
is folder) named with the backend user name. And in the backend user
module you can set the permission(Not for the group user but for the
single backend user only).
if the backend user is too much. and You just wanna set permissions for the group and all backend users are sharing the same rules. You can refer to Hook:https://docs.typo3.org/p/georgringer/news/main/en-us/Tutorials/ExtendNews/Hooks/Index.html so that the basic logic is like this:
2.1 get current logged-in user group.
2.2 if the group is Reporter, we can use the hook for the listing page:
$constraints[] = $query->equals('cruser_id', $be_id);
Edit(3/3/2022):
Hi Chris, Yes you are right.
Today, I have got a chance to dig into the news extension. I think we can still make it by the hook
in your ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][\TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList::class]['modifyQuery'][$_EXTKEY]
= \T3docs\SitePackage\Hooks\DatabaseRecordListHook::class;
(Please make sure the namespace is correct)
within the file : T3docs\SitePackage\Hooks\DatabaseRecordListHook.Create a function named modifyQuery:
public function modifyQuery($parameters,
$table,
$pageId,
$additionalConstraints,
$fields,
$queryBuilder)
{
if ($table === 'tx_news_domain_model_news') {
$tsconfig = $GLOBALS['BE_USER']->getTSConfig();
if (!empty($tsconfig['options.']['be_users'])) {
$be_users = $tsconfig['options.']['be_users'];
$queryBuilder->andWhere('cruser_id IN (' . $be_users . ')');
}
}
return $queryBuilder;
}
in the user Options tab set Tsconfg : options.be_users = 3,100
(3,100 is the be_user id. And the 2 two backend users's news will show up)
thus, it works for me.

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...?

Laravel: update database record without having to set properties one by one

I'm updating a db record in laravel using eloquent like this:
($request is an object with the properties I want to update)
$book = Book::find($request->id)
$book->title = $request->title;
$book->author = $request->author;
$book->publisher = $request->publisher;
.
.
.
$book->something = $request->something;
$book->save();
It works fine but I wonder if it's possible to do it whitout having to explicity name the properties one by one since the names in $request are exactly the same as those of the model, something like:
$book = $request;
$book->save();
$book = Book::find($request->id);
$book->update($request->all());
More info here https://laravel.com/docs/5.6/queries#updates
However, before doing so, you will need to specify either a fillable or guarded attribute on the model, as all Eloquent models protect against mass-assignment by default.
A mass-assignment vulnerability occurs when a user passes an unexpected HTTP parameter through a request, and that parameter changes a column in your database you did not expect. For example, a malicious user might send an is_admin parameter through an HTTP request, which is then passed into your model's create method, allowing the user to escalate themselves to an administrator.
Read more about in documentations.

TYPO3 7.6 load backend user info

I've added my own scheduler task to the TYPO3 that will, for example, create new page if necessary. The scheduler runs by a special _cli_scheduler user and if I create new pages with it, other editors may not see it.
I'm using the DataHandler (former TCE) to create new pages. The start() method accepts an optional parameter - alternative user object that will be used as a creator of the page.
Having uid of an editor user, how can I fully instantiate the \TYPO3\CMS\Core\Authentication\BackendUserAuthentication object which then I provide to the DataHandler::start()?
I was thinking of using the object manager to get new instance of the mentioned class and just set the uid on it, but the DataHandler checks some other properties of the BackendUserAuthentication object, like permissions, etc.
What is the correct way for getting BackendUserAuthentication object will all user data? Is there any factory or a repository I could use?
No one was able to help me with this, so I started digging. After some reverse engineering I have found a complete way for loading any backend user as long as you know their ID. I have created a read-only repository with the following method:
public function fetchById($userId)
{
/** #var BackendUserAuthentication $user */
$user = $this->objectManager->get(BackendUserAuthentication::class);
$user->setBeUserByUid($userId);
$user->resetUC();
$user->fetchGroupData();
$user->getFileStorages();
$user->workspaceInit();
$user->setDefaultWorkspace();
return $user;
}
It will do the following:
Load user record from database and store it internally in the $user property
Load the UC of the user
Load user/group permissions
Initialize file storage
Initialize workspace
I've dumped user created by this method and compared with the currently logged-in user and it seems that all necessary properties have been set up.
Please let me know if I missed something.

How to display just students in users page(Moodle:/admin/user.php)

I want to display just students in moodle users page without manually adding a filter using the web interface. Could anybody help me on how to do?
You can create a link that shows only students but you'll need to post the data. Here's how I did it.
If you install WebDeveloper - http://chrispederick.com/work/web-developer/
Then go to /admin/user.php and click WebDeveloper, choose the "Forms" tab and "convert POSTS to GETS".
Choose the filter and click add filter. This will display a url with all the form fields. Moodle is expecting a POST rather than a GET though.
So copy and paste the url into a variable and use the single_button function with the post method eg:
$url = '/admin/user.php?sesskey=xxxxxxx&_qf__user_add_filter_form=1&mform_showmore_id_newfilter=1&mform_isexpanded_id_newfilter=1&realname_op=0&realname=&lastname_op=0&lastname=&firstname_op=0&firstname=&email_op=0&email=&city_op=0&city=&country_op=0&confirmed=&suspended=&profile_fld=0&profile_op=0&profile=&courserole_rl=5&courserole_ct=0&courserole=&systemrole=0&cohort_op=2&cohort=&username_op=0&username=&auth=&deleted=&addfilter=Add+filter';
echo $OUTPUT->single_button($url, get_string('student'), 'post');
Copy and paste your own url rather than the above.
You can probably remove a lot of the parameters. You should also get the roleid for the student and use the moodle_url function, eg:
$studentroleid = $DB->get_field('role', 'id', array('shortname' => 'student'));
$params = array('courserole_rl' => $studentroleid, 'courserole_ct' => 0, ... );
$url = new moodle_url('/admin/user.php', $params);
echo $OUTPUT->single_button($url, get_string('students'), 'post');
This is not possible, as, in Moodle, it is rare for someone to be assigned the role of 'student' at the system level (and if you did, they would have access to every course on the site).
The concept of 'student' in Moodle only makes sense at the course level.