Sulu CMS: is it possible to restrict access to certain attributes of a specific template to certain roles? - sulu

We have a situation where we have two different roles of users: let's call them content_labourer and content_boss. There's a template we could call very_cool_content. On this template we've stated the following attributes:
title: some string value
api_content_id: an integer that accurately binds this content to some backend API content (we use this in our VeryCoolContentController to fire up some backend API stuff, obviously)
description: a text value
I want my content_boss to be able to set the value for all these attributes. After all, he's the boss.
However, my content_labourer is not privy to the whole API business and would never in a million years know which value he should enter there, let alone that he should even be able to enter/change the value of api_content_id. He should also not be able to set the value of title, because that's none of his business.
Now my question is: how do I protect these particular attributes from being changed by (or in the ideal case: even be visible to) users without the content_boss role?

I am sorry, but it is not possible to restrict access to single fields. But what you can do is to restrict the access to an entire page. Maybe you can make use of that instead, if you restructure your content somehow?

Related

RESTful API, query params on PUT

I am struggling with developing an API that follows RESTful best practices for my use case.
My db model looks something like:
Company:
Id
Name
Location:
Id
Name
DefaultSetting
LocationSettings:
Id
LocationId
CompanyId
Setting
In the business model, not every company has set location values, so in many cases it will default to the value from Location. If the user decides to change the value, then we will store their custom settings instead of using the default.
I was thinking of an API along the lines of:
GET /location-settings?companyId=id
GET /location-settings?companyId=id&locationId=id
PUT /location-settings?companyId=id&locationId=id
The idea is that when a user decides to change any setting, we will invoke the PUT route - it will update the location settings if custom settings exist for this company, or create a new entry in LocationSettings if it does not exist.
However, this seems like it might be an anti-pattern as normally I do not see query parameters used in such a manner on PUT routes to specify which resource to update. In this case, I cannot easily provide an ID for the location-settings resource because it may or may not exist. I did not want to use 2 separate routes (one for PUT and one for POST) because in the application's use-case this would get confusing i.e. from an end-user's perspective the default settings logic is hidden, so they always have location settings for their company and are simply updating them.
Another option I was thinking of was (OPTION 2):
GET /location-settings?companyId=id
GET /location-settings/locations/{locationId}?companyId=id
PUT /location-settings/locations/{locationId}?companyId=id
However, this seems strange because locations is not a sub-resource of location-settings.
A 3rd option I was considering was (OPTION 3):
GET /locations/location-settings?companyId=id
GET /locations/{locationId}/location-settings?companyId=id
PUT /locations/{locationId}/location-settings?companyId=id
Personally I liked this option the best. However, I am not sure that referencing 2 collections like the first get route does without an ID is a good REST practice.
Any recommendations on this?
It sounds like every company only has 1 'location-settings'.
If that that's true, you don't really need to add the location settings id to the url.
I might be wrong, but it seems like the only 2 routes you need are:
GET /company/{id}/location/{locId} - Return custom location settings OR default
PUT /company/{id}/location/{locId} - Update custom location for location
I do not see query parameters used in such a manner on PUT routes to specify which resource to update.
That's true, you don't. But there is nothing wrong with doing it that way
PUT /x/y/z
PUT /x?y=z
Both of those URI are fine; general purpose components will do the right thing, URI templates describe them easily, and so on. There are tradeoffs between them, of course (convenience for html vs convenience of relative references); but you could easily have one of them re-direct to the other if you discovered later that you wanted to change things.

Good URL syntax for a GET request with a composite key

Let's take the following resource in my REST API:
GET `http://api/v1/user/users/{id}`
In normal circumstances I would use this like so:
GET `http://api/v1/user/users/aabc`
Where aabc is the user id.
There are times, however, when I have had to design my REST API in a way that some extra information is passed with the ID. For example:
GET `http://api/v1/user/users/customer:1`
Where customer:1 denotes I am using an id from the customer domain to lookup the user and that id is 1.
I now have a scenario where the identifier is more than one key (a composite key). For example:
GET `http://api/v1/user/users/customer:1;type:agent`
My question: in the above URL, what should I use as the separator between customer:1 and type:agent?
According to https://www.ietf.org/rfc/rfc3986.txt I believe that the semi-colon is not allowed.
You should either:
Use parameters:
GET http://api/v1/user/users?customer=1
Or use a new URL:
GET http://api/v1/user/users/customer/1
But use Standards like this
("Paths tend to be cached, parameters tend to not be, as a general rule.")
Instead of trying to create a general structure for accessing records via multiple keys at once, I would suggest trying to think of this on more of a case-by-case basis.
To take your example, one way to interpret it is that you have multiple customers, and those customers each may have multiple user accounts. A natural hierarchy for this would be:
/customer/x/user/y
Often an elegant decision like this can be made, that not only solves the problem but also documents your data-model in a way that someone can easily see that users belong to customers via a 1-to-many relationship.

How to properly access children by filtering parents in a single REST API call

I'm rewriting an API to be more RESTful, but I'm struggling with a design issue. I'll explain the situation first and then my question.
SITUATION:
I have two sets resources users and items. Each user has a list of item, so the resource path would like something like this:
api/v1/users/{userId}/items
Also each user has an isPrimary property, but only one user can be primary at a time. This means that if I want to get the primary user you'd do something like this:
api/v1/users?isPrimary=true
This should return a single "primary" user.
I have client of my API that wants to get the items of the primary user, but can't make two API calls (one to get the primary user and the second to get the items of the user, using the userId). Instead the client would like to make a single API call.
QUESTION:
How should I got about designing an API that fetches the items of a single user in only one API call when all the client has is the isPrimary query parameter for the user?
MY THOUGHTS:
I think I have a some options:
Option 1) api/v1/users?isPrimary=true will return the list of items along with the user data.
I don't like this one, because I have other API clients that call api/v1/users or api/v1/users?isPrimary=true to only get and parse through user data NOT item data. A user can have thousands of items, so returning those items every time would be taxing on both the client and the service.
Option 2) api/v1/users/items?isPrimary=true
I also don't like this because it's ugly and not really RESTful since there is not {userId} in the path and isPrimary isn't a property of items.
Option 3) api/v1/users?isPrimary=true&isShowingItems=true
This is like the first one, but I use another query parameter to flag whether or not to show the items belonging to the user in the response. The problem is that the query parameter is misleading because there is no isShowingItems property associated with a user.
Any help that you all could provide will be greatly appreciated. Thanks in advance.
There's no real standard solution for this, and all of your solutions are in my mind valid. So my answer will be a bit subjective.
Have you looked at HAL for your API format? HAL has a standard way to embed data from one resources into another (using _embedded) and it sounds like a pretty valid use-case for this.
The server can decide whether to embed the items based on a number of criteria, but one cheap solution might be to just add a query parameter like ?embed=items
Even if you don't use HAL, conceptually you could still copy this behavior similarly. Or maybe you only use _embedded. At least it's re-using an existing idea over building something new.
Aside from that practical solution, there is nothing in un-RESTful about exposing data at multiple endpoints. So if you created a resource like:
/v1/primary-user-with-items
Then this might be ugly and inconsistent with the rest of your API, but not inherently
'not RESTful' (sorry for the double negative).
You could include a List<User.Fieldset> parameter called fieldsets, and then include things if they are specified in fieldsets. This has the benefit that you can reuse the pattern by adding fieldsets onto any object in your API that has fields you might wish to include.
api/v1/users?isPrimary=true&fieldsets=items

REST where should end point go?

Suppose there's USERS and ORDERS
for a specific user's order list
You could do
/user/3/order_list
/order/?user=3
Which one is prefered and why?
Optional parameters tend to be easier to put in the query string.
If you want to return a 404 error when the parameter value does not correspond to an existing resource then I would tend towards a path segment parameter. e.g. /customer/232 where 232 is not a valid customer id.
If however you want to return an empty list then when the parameter is not found then query string parameters. e.g. /contacts?name=dave
If a parameter affects an entire URI structure then use a path e.g. a language parameter /en/document/foo.txt versus /document/foo.txt?language=en
If unique identifiers to be in a path rather than a query parameter.
Path is friendly for search engine/browser history/ Navigation.
When I started to create an API, I was thinking about the same question.
Video from apigee. help me a lot.
In a nutshell when you decide to build an API, you should decide which entity is independent and which is only related to someone.
For example, if you have a specific endpoint for orders with create/update/delete operations, then it will be fine to use a second approach /order/?user=3.
In the other way, if orders have only one representation, depends on a user and they don't have any special interaction then you could first approach.
There is also nice article about best practice
The whole point of REST is resources. You should try and map them as closely as possible to the actual requests you're going to get. I'd definitely not call it order_list because that looks like an action (you're "listing" the orders, while GET should be enough to tell you that you're getting something)
So, first of all I think you should have /users instead of /user, Then consider it as a tree structure:
A seller (for lack of a better name) can have multiple users
A user can have multiple orders
An order can have multiple items
So, I'd go for something like:
The seller can see its users with yourdomain.com/my/users
The details of a single user can be seen with yourdomain.com/my/users/3
The orders of a single user can be seen with yourdomain.com/my/users/3/orders
The items of a single order can be seen with yourdomain.com/my/users/3/orders/5

Master Data Services - Domain based attributes

We are using Master Data Services as an MDM solution for our SQL Server BI environment. I have an entity containing a first name and last name and then I have created a business rule that concatenates these two fields to form a full name which is then stored in the "name" system field of the entity.
I use this as a domain based entity in another entity. Then the user can then see the full name before linking it as a attribute in the second entity.
I want to be able to restrict the users from capturing data in the first entity against the name attribute because the business rule deals with the logic to populate this attribute. I have read that there are two ways to do this:
Set the display width to zero of the attribute. This does not seem to work, the explorer version still shows a narrow version of the field in the rows and the user can still edit the field in the detail pane.
Use the security to make the attribute read only. I have tried different combinations of this but it seems that you cannot use this functionality for a name field (system field).
This seems like pretty basic functionality that I require and it seems that there is no clear cut way to do this in MDS.
Any assistance will be appreciated.
Thanks
We do exactly the same thing.
I tested it, and whether you create a new member, or edit an existing member, the business rule just overwrites the manual input value in the name attribute.
Is there a specific 'business' reason why you need to restrict data input in the name field? If it is for Ux reasons, you can change the display name of the name attribute to something like 'Don't populate' or alternatively make it a '.', then the users won't know what to input.