Assign site template to organization site programmatically in liferay 6.1.0 - liferay-6

I have created user & organization pragmatically using addUser() & addOrganization() methods respectively.
I am also able to add users to this organization using addOrganizationUsers() method.
Now I have created a site template from liferay control panel.
As we know , we can create a site for organization, and while creating a site we have options to select a site template for public & private pages.
As we know .
Public page - Visible to members + non members
Private page - Visible to only members.
So I want to create a organization site with private pages only so it will be seen by only organization member.
OrganiztionLocalServiceUtil.addOrganization(
long userId, long parentOrganizationId, String name, String type,
boolean recursable, long regionId, long countryId, int statusId,
String comments, boolean site, ServiceContext serviceContext)
Using above method , by specifying boolean site value 'true' a site will get created.
Now I want to add a site template to this organization site pragmatically which I have created from control panel.
So is there any API to add site template to any site of organization

Unfortunately there is no public API for it.
Use LayoutSetPrototypeLocalServiceUtil to get the ID for the SiteTemplate. To get the SiteTemplate by name you'll have to either use a dynamicQuery or iterate over the result of LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototypes(-1, -1)
Then invoke applyLayoutSetPrototypes of SitesUtil in the context of the portal.
MethodKey methodKey = new MethodKey("com.liferay.portlet.sites.util.SitesUtil","applyLayoutSetPrototypes", Group.class, long.class, long.class, ServiceContext.class);
PortalClassInvoker.invoke(false, methodKey, organization.getGroup(), publicLayoutSetId, privateLayoutSetId, serviceContext);
Specify -1 for publicLayoutSetId.
An Admin has to be logged in to perform this action.
To perform this action on startup or in the background a new ServiceContext would be needed.
Something like the following
ServiceContext serviceContext = new ServiceContext();
serviceContext.setAddGroupPermissions(true);
serviceContext.setAddGuestPermissions(true);
serviceContext.setSignedIn(false);
// set the following to an admin user / company or default user
User user = UserLocalServiceUtil.getDefaultUser(companyId); // or any user that has the permissions
serviceContext.setUserId(user.getUserId());
serviceContext.setCompanyId(companyId);
And most likely you also have to setup the ThreadPermissionChecker
PrincipalThreadLocal.setName(user.getUserId());
PermissionChecker adminPermissionChecker = PermissionCheckerFactoryUtil.create(user, false);
PermissionThreadLocal.setPermissionChecker(adminPermissionChecker);
Don't forget to reset the permission checker in a final block otherwise the same permission checker might be used for other requests on the same thread.

Related

how to set Internal/Subscriber role as default role to all authenticated users in WSO2 Api manager?

i am trying to give default role as Internal/Subscriber to all users.
i made changes in we made changes in file /_system/config/apimgt/applicationdata/tenant-conf.json and added role such as to Internal/creator,Internal/everyone,apimrole
"Name": "apim:subscribe",
"Roles": "admin,Internal/creator,Internal/everyone,apimrole,Internal/subscriber"
it gives me below error
org.wso2.carbon.apimgt.api.APIManagementException: Error while adding the subscriber
laxman#gmail.com#carbon.super#carbon.super
any help appreciated
New user creation takes place in the WSO2 API Manager in two ways.
Through the management console of the API Manager
Self signup
In 1st way you can assign roles when creating users.
For self signed-up users there already exists a handler to assign Internal/subscriber role to the new users who are having Internal/selfsignup role.
To assign role: Internal/subscriber to new users or existing role not assigned users we have below two options:
Option 1
If you wish to assign subscriber role to existing role not assigned users using Management Console, then you can go to roles listing page there:
There is an option: Assign Users in Actions column in role list relevant to Internal/subscriber role.
It will list all the users who have not assigned Internal/subscriber role and there are several options to select many users at once and assign the role.
Option 2
You can write a custom user operation event listener and add it as OSGI bundle.
In this case you can refer this WSO2 IS doc and write a event listener extending AbstractIdentityUserOperationEventListener.
This sample code worked for me:
public class SampleEventListener extends AbstractIdentityUserOperationEventListener {
private static final String EVENT_LISTENER_TYPE = "org.wso2.carbon.user.core.listener.UserOperationEventListener";
private static final String SUBSCRIBER_ROLE = "Internal/subscriber";
#Override
public boolean doPreAddUser(String userName, Object credential, String[] roleList, Map<String, String> claims,
String profile, UserStoreManager userStoreManager) throws UserStoreException {
List<String> roles = new ArrayList<>(Arrays.asList(roleList));
if (!roles.isEmpty() && !roles.contains(SUBSCRIBER_ROLE)) {
userStoreManager.updateRoleListOfUser(userName, new String[]{}, new String[] { SUBSCRIBER_ROLE });
}
return true;
}
This will add Internal/subscriber role to each newly adding user, if the user doesn't have that role in the process of adding new user.
Here it has mentioned multiple interfaces with which you can implement User Store Listeners.
For OSGI bundle creation and deployment process you can find this sample GitHub project. You can copy the built jar file to the directory <APIM_HOME>/repository/components/dropins/ by following the steps have been mentioned there. (Since WSO2 API Manager is also using WSO2 IS components you can follow the same steps mentioned in README with the API Manger as well)
You can go through this blog post to get complete idea about OSGI bundling.

How to implement dynamic creation of permission groups with different set of endpoints Django Rest Framework

In my project I have lot of endpoint views (APIViews, ViewSets). For all of them now I set permissions, some of them are default (e.g. AllowAny) and some are custom created:
permission_classes = (IsUserHaveSomePermission,)
Now I want to implement some flexible system, that will allow me to specify set of allowed endpoints for each user, for example:
On front-end I want to select some user and have a list of checkboxes that correspond to project's endpoints.
This is just an utopian solution, some details may be changed, but the main question is to how make something similar so that admins can basically dynamically change list of allowed endpoints/views for user?
thanks in advance
This solution can be implemented by storing if the user has permission to access the current request method and request path.
Create a new db model for storing the user, request method and request path. Lets say the name of the model is RequestPermission
Instead of the path you can store a constant representing the url so that you have the flexibility of editing the path later on. This constant can be the url name which is supported by django.
class RequestPermission(models.Model):
user = user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='request_permissions')
method = models.CharField(max_length=10)
path_name = models.CharField(max_length=200)
create a custom permission class:
class IsUserResuestAllowed(permissions.BasePermission):
def has_permission(self, request, view):
user = request.user
# you can choose how to get the path_name from the path
path_name = get_path_name(request.path)
return RequestPermission.objects.filter(user=user, method=request.method, path_name=path_name).exists()
Now you can use this class as the default permission class in rest framework settings or use it per view.

How to include a user manager to another application for ASP.NET Core 3.1

I'm developing two different applications, I will name them A and B.
A is an internet platform, where you can logon only if you have a valid user account.
B is an intranet platform, where users can authenticate via Active Directory. An administrator using application B should be able to create new user accounts for application A.
After the creation of a new user account, I want to be able to realize different functions, for example to send an e-mail to the registered mail address, so the new user can change the default password.
All the functionalities that I want to implement, can be done by the UserManager (see section "Use another app to add users" in the following link: https://learn.microsoft.com/en-us/aspnet/core/security/authentication/scaffold-identity?view=aspnetcore-3.1&tabs=visual-studio#disable-register-page).
Based on this I implemented the following code:
public class ControllerClass : Controller
{
private readonly HelperClass _helper;
private readonly UserManager<IdentityUser> _userManager;
public ControllerClass (UserManager<IdentityUser> userManager)
{
_userManager = userManager;
_helper= new HelperClass (userManager);
}
}
public class HelperClass
{
private readonly DbContext _db;
private readonly UserManager<IdentityUser> _userManager;
public HelperClass (UserManager<IdentityUser> userManager)
{
_db = new DbContext ();
_userManager = userManager;
}
private async Task<string> EnsureUser(string userName, string userPassword)
{
var user = await _userManager.FindByNameAsync(userName);
if (user == null)
{
user = new IdentityUser()
{
UserName = userName
};
await _userManager.CreateAsync(user, userPassword);
}
return user.Id;
}
internal async void CreateUser(UserVM uvm, int id)
{
var userId = await EnsureUser(uvm.userName, uvm.userPassword);
// TODO ...
}
}
Unfortunately I didn't manage to include the UserManager into my application B. I got the following error message: "An unhandled exception occurred while processing the request.
InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Identity.UserManager`1[IdentityUser]' while attempting to activate 'ControllerClass '."
Do you have an idea, how I can add the UserManager to manage the users for another application?
Well, the specific error you're getting is simply because UserManager<TUser> is not registered in the service collection. In order to inject anything, you must first register it. In your actual user-facing app, that's being done by services.AddIdentity(). However, that does a lot more than just register UserManager<TUser>, so you shouldn't just run off and add the same command to your second app.
You could add a registration for it specifically:
services.AddScoped<UserManager<ApplicationUser>>();
However, it actually has a ton of dependencies, each of which would also need to be registered. If you look at the constructor, there's seven services not registered out of the box, many of which have their own dependency trees. Long and short, it's a pain. There's also the matter of separation of concerns, here. This would require adding in the whole data layer from the other app.
Your best bet is to simply expose an API on the Identity app (and lock it down, of course). That way, all the logic of working with users stays with the rest of that logic. The administration app, then, can call out to the API to add, update, delete, etc. users without having to have knowledge of how that's actually done.
Answering after 2 years. For future reader, You can use
services.AddIdentityCore<IdentityUser>();
which adds necessary services that are for user-management add/delete etc. without adding Login service.
to add EntityFramework you can create context and use like this
services.AddDbContext<ApplicationAuthDbContext>(options =>
{
// Configure the context to use postgresql.
options.UseNpgsql(config.GetConnectionString("AuthDbContext"))
.UseSnakeCaseNamingConvention();
});
services.AddIdentityCore<IdentityUser>()
.AddEntityFrameworkStores<ApplicationAuthDbContext>();
For more information
https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.identityservicecollectionextensions.addidentitycore?view=aspnetcore-6.0

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.

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.