Monthly Archives: April 2021

Team membership and access permissions – how are they related?

When we have a team and a bunch of users added to the team, would you expect every user to have access to whatever another user has access to? Since, after all, they are all team members, so should not they be sharing the data?

Basically, what if we have the following set up:

image

Is that “Other User” going to be able to see the email assigned to the “Owner” assuming both users are members of the same team?

The answer is not that straightforward, since what happens next depends on the security roles assigned to the users and to the team.

If the team does not have any roles assigned to it, and if “Other User” can’t see that email normally, then, by adding both users to the same team, we are not, really, changing security permissions of the “Other User”. Which means “Other User” still can’t see the email assigned to the “Owner”.

Now let’s look at the access levels in CDS:

image

If we created a security role and set it up to that it would have “business unit”, “parent…”, or “organization” access level to the activities (and assuming both users are in the same BU), then, by assigning that role directly to the “Other User” we would grant that user access to the email above.

We could do the same by assigning that role to the team instead, since the user would inherit permissions from the team.

But, so far, all we’ve done – we’ve shared all emails in the business unit and/or in the organization with the members of that team (or with the user directly).

What if we only wanted to share “Owner” user emails with the “Other User”? Would it be doable without resorting to the sharing/access teams?

The way owner security is designed is that the system will be looking at who owns the record, and, then, it would be validating user access by looking at that user’s permissions. Such permissions can either be given to the user directly (through a security role), or they can be inherited from a team.

But, in either case, there will be a record owner, and there will be a user trying to access that record, and that’s what the system will be looking at. They are both on the same team? It does not matter.

To illustrate this behavior, let’s create a security role that has “user-level” access to the activities:

image

This security role has now been assigned to the team below:

image

And there are a couple of users in that team. I am still a System Admin, so, when looking at the phone calls in the system, I can see a phone call assigned to the System Account:

image

So what if I stopped being a System Admin? There are no other roles assigned to me(except for the Customer Service app access and a custom “support user” role which will allow me to promote myself to an admin again), so I’d only have access to the activities through the role inherited from the team. Am I going to see that phone call assigned to my team member?

Just as expected, it’s not there:

image

But we are not done yet. What if that phone call were assigned to the team instead?

That is a different scenario now. As a member of the team, I can still see that record:

image

Basically, the ownership is sort of extended from the team to the team members (from the access perspective), but it’s not passed from one team member to the other.

That’s just something to keep in mind when setting up the security model – hope this helps!

Power Apps Portals: redirecting newly registered users to a custom page

When registering on the portal, users are, normally, redirected to the  profile page by default. It seems, though, this is not, really, configurable, through the portal settings, so is there a workaround?

image

It seems this should be doable, but, first, let’s look at another screenshot here:

image

What this means is that, once a user is registered, they’ll be redirected to the profile page, but returnUrl part of the query is not always the same. What stays the same is “profile/?ReturnUrl”, though, so let’s just add a redirect?

But not this redirect:

image

Because, as a number of folks have pointed out before me, a redirect will only work when that path does not exist. As in… if it were profile_PAGE_NOT_EXISTS for the Inbound URL, it would work. But, since there is a profile page, the redirect won’t kick in at all.

Instead, we can add a bit of code to the site header like this (I’ve highlighted the added part):

image

And voila – it’s working now:

So, why using javascript and not Liquid? I could try something like this instead:

{% if request.url contains ‘profile/?ReturnUrl’ and page.title startswith ‘Profile’ %}
     <script>if(window.location.href = “/welcome”;</script>
{% endif %}

Somehow, neither the “request” nor the “page” objects get updated when there is a client-side redirect through window.location, so that’s the only reason for using a purely javascript-based approach.

Well, don’t get bored – have fun!

Let’s have some fun – here is “Social Hype” monitoring Power App

The other day, I was wondering if I could, somehow, come up with an app that would be tracking twitter mentions of certain keywords, and, then, do some analytics on top of that.

And you know what? It took me 4 hours in total to get it up and running on Power Platform – the screen below is an illustration of how it worked out:

image

Forgive me, Microsoft. I tried making your bar higher, but Amazon has definitely taken the lead, and, then, there is Apple… but, at least, Tesla is lagging behindSmile 

What’s involved there?

There are a few pieces so far:

image

  • I’m using Twitter as a “data source”
  • In order to get the data from Twitter, I’m using a Power Automate flow
  • All the data is, then, stored in Microsoft Dataverse
  • And there is a Model-Driven Power App to present that data and to configure the search queries

With this in place, I could, now, add Power BI to the mix and start doing more analytics as I keep getting more data. I could also add other social platforms to the mix and start collecting data from there. Potentially, I might have to start creating custom connectors or add Azure Functions, too. The sky is the limit in terms of how advanced and how complex this can be, but that’s fine. Most importantly, it took almost no time not only to prototype the app, but to get a working version that’s already yielding some interesting output.

So, then, if you wanted to try it out, here is what’s involved:

1. Download solutions from git – there are both managed and unmanaged versions

https://github.com/ashlega/ItAintBoring.SHPMonitoring/tree/master/Solutions

2. Import managed solution into your environment – you’ll have to configure connections along the way

Just make sure to use maker portal – don’t use classic experience or those connections won’t be configured properly

image

I am assuming you have a twitter account, btwSmile

3. Once you have it imported, configure your first monitor

Open “Social Hype Monitoring” app and choose “SHP Monitors” in the navigation pane:

image

Start creating a new one – here is how you can set it up, for example:

image

For the search Query, since it’s only working with Twitter at the moment, here is a link to the Twitter search query syntax: https://developer.twitter.com/en/docs/twitter-api/v1/rules-and-filtering/search-operators

  • Once the monitor record above is created, it may take some time (up to an hour) before a Power Automate flow that’s scheduled to run every hour kicks in and starts processing those monitor records. Once it does kick in, you’ll start seeing data coming in. Here is how it may look like:
  • image

Each of those “SHP Monitor” records will have “SHP Stats” records linked to it. Those correspond to the individual data collection runs:

image

So, over time, there will be more of those for each SHP Monitor (and this is why there is “Frequency” column – that’s how you can control how often data collection should be happening).

And, yes, there are a few charts, though it becomes a little tricky. Charts are not available for subgrids (unlike in the classic interface), but you can still show/hide a chart if you navigate to Related->SHP Stats for a specific monitor:

image

In the meantime, I’m thinking of a bunch of things I could probably showcase using this app, so, maybe, that’s what’s coming next?

Have fun!

Adding CRUD to Virtual Entities

As everybody else has already noticedSmile, CRUD support has been added to the Virtual Entities:

https://docs.microsoft.com/en-us/powerapps/developer/data-platform/virtual-entities/sample-ve-provider-crud-operations

A while ago, I blogged about how we can use canvas apps with virtual entities, and there was a sample plugin there:

https://www.itaintboring.com/dynamics-crm/virtual-entities-revisited-setting-up-a-virtual-entity/

So, I figured, I’d just try updating that plugin to support create/update/delete. Since it is, already, supporting Retrieve and RetrieveMultiple.

It seems this should be really simple. All the details about the virtual record are supposed to be passed through the “Target” parameter of the plugin context

  • On “Create”, I should have the record being created there, as an Entity
  • On “Update”, I should have the record being update there, as an Entity
  • On “Delete”, I should have the record being delete there, but as an EntityReference this time

Updating the plugin did not take long, and you’ll see the code in git. Although, turned out I had to download updated version of the plugin registration utility, since, otherwise, there was no support for create/update/delete:

image

Actually, if you look at that screenshot above, there seem to be a remnant of how it used to work. There is still that note. That’s the past, we are in the present, so moving on!

Ok, let’s set it all up – I mean, let’s update data provide settings:

image

And click “update”… and there is an exception:

image

Not sure why that happened, but, apparently, registering a completely new data source worked:

image

Here it is, my new data source with a new data provider:

image

Why did it fail when I tried updating the original one? Not sure at the moment, but, with this new data source, I wonder if I can use it with the existing virtual entity. Otherwise, it would be a problem… so, let’s try that out.

Let’s go to the virtual entity configuration in the solution and pick the new data source:

image

Actually, that always gets me. There is no new data source. Not yet. First, we have to go to the Settings->Administration and create a new data source, even if that may sound a little counterintuitive. Did not we create a data source in the plugin registration tool? But we do have to add it to the list of Data Sources in the administration area – there are always these two steps involved:

image

Why do we need to define “data sources” in two different places? Not sure.

Now that it’s there, I can choose this new data source for my existing Virtual Entity:

image

Just had to add another main form (since the old one had that canvas app on it), and…

image

That’s a bummer. But… maybe, that “upgrade” path is not working yet? Let’s create a new virtual entity. An hour later, there is a new virtual entity and the plugin has been adjusted to fix a few bugs related to nulls, but, in the end, here we go:

It was, after all, a problem with the upgrade. Looks like that original entity has been somehow marked as “readonly” (might need to dig into the metadata, but that’s for another time).

I guess there are still limitations there (using advanced find, security roles, etc), but, with the CRUD support now… there is quite a bit more we should be able to use virtual entities for, eh?

PS. And here is a link to the updated date provider solution in git: https://github.com/ashlega/ITAintBoring.VirtualEntities