Query list items based on what permissions they have - sharepoint

Don't know how to google for such, but is there a way to query all the items where
Permissions are unique to listitem
These unique permissions contains assignment for specific group X.

Old post, but still getting plenty of views and I can't find anywhere more relevant to say this. There are some shortcuts available now, and you can use CAML to return only items with unique permissions, just not using the HasUniqueRoleAssignments property.
Sharing/setting unique permissions on a list item adds hidden "Field" nodes ("SharedWithDetails" & "SharedWithUsers") to it's SchemaXml property, which you can filter with CAML:
<View><Query><Where><IsNotNull><FieldRef Name='SharedWithDetails' /></IsNotNull></Where></Query></View>
Incidentally, setting a unique permission on an Item also seems to add a flag to the List itself, which is presumably how the /_layouts/15/uniqperm.aspx page manages to return answers on biiiig sites so quickly (and the cryptically vague "Lists that may contain items with unique permissions" message). You use this additional XML to identify lists that (probably) contain Items with unique permissions, which is vastly more efficient than enumerating every Item in the List to find out if any of them had unique permissions. This is particularly valuable if your Site contains many Lists, or any large Lists.
This PnP PowerShell code returns all lists that (probably) have items with unique permissions:
Get-PnPList -Includes SchemaXml | ? {$_.SchemaXML -match "SharedWithDetails"}
And once you have the list, you can use Get-PnPListItem and the above CAML query to efficiently return only the Items with unique permissions without having to enumerate/load every item in the List:
Get-PnPListItem -List [YourList] -Query "<View><Query><Where><IsNotNull><FieldRef Name='SharedWithDetails' /></IsNotNull></Where></Query></View>"

You will have to loop through the items and inspect the permissions item per item and update them if relevant. The more items you have the longer it takes. So not really a great solution.
An other solution is using the credentials of a user that is only member of group x.
SharePoint automatically takes permissions into account. So if you connect to the list using that user, you should only get the items on which the user has permissions.
Use the NetworkCredentials class for doing this.
Then use a CAML query to update your items.
--W

I don't think you can do this by shaping a CAML query and using the SPQuery object to get the items in this way.
My thinking would be to get all items, and loop through them testing for the HasUniqueRoleAssignments and RoleAssignments properties.

Related

CouchDB: In a checklist app, new file for every list item?

I'm working on a checklist web app
Now, every user can have lots of check lists, each with many items on them.
Would it be a good idea to keep the items in a JS object in the individual checklist? This would have been my first approach, since there wouldn't be a lot of sorting or anything happening on those items.
Now I'm thinking about putting every item in an individual file (because I might do stuff like deadlines and assignments for individual items)
This seems like a lot of files to me. Maybe I underestimate CouchDB. Would this be a good approach to the problem?
Store every list item as new document.
Every list item document should have properties like listname, deadline and/or assignment.
You don't need (but you can have) extra docs to express hierarchy or nested relations. That what CouchDB views for - e.g. you will build a view getListItemsByListname with the listname as key to get all items of one list.

Get List Item by Guid without List in SharePoint

Could anybody help me to get List Item by unique Id in SharePoint without using List? I know the List Item unique Id, but I haven't information about List. Using Client Object Model I can do the following:
using (SP.ClientContext clientContext = new SP.ClientContext(...))
{
**SP.List list = clientContext.Web.Lists.GetById(listId);**
SP.ListItem listItem = list.GetItemById(listItemId);
clientContext.Load(listItem);
clientContext.ExecuteQuery();
...
}
Unfortunately, in this code I use listId, but the problem is that in my task I don't know listId, I have only ListItem Guid. Since I have unique Id, I believe that there must be a way to get this Item without using any additional information.
You've posted a snippet with a Client Object Model, so I suppose it's a preffered object model for the solution. However, if it's acceptable for You, I've found some information on how to achieve this using server side object model, which You may find helpful.
It seems that this can be done using SPWeb.GetFile(Guid itemGuid) if the item exist in the root site.
If you want it to work also for subsites, you can use SPWeb.GetSiteData method to invoke caml retrieving an item as explained in this article: http://www.chakkaradeep.com/post/Retrieving-an-Item-from-the-RootWeb-and-Subwebs-using-its-UniqueId.aspx.
You can also take a look at this thread on SO for some additional information:
SharePoint: Get SPListItem by Unique ID.
If you have any issues using those methods, let me know. I'll also look for alternatives for this to run with Client Object Model and I'll post them if I find some, however, it seems to be more difficult to achieve.

sharepoint - get items from lists in multiple webs

Let's say I have a site level feature that has a content type, and a web level feature that has a list instance with items of the previously mentioned content type. If I enable the web feature for 100+ different webs, so I get 100+ lists from the same list instance definition and content type, what's the fastest way to get items from all those lists? Iterating through the webs and getting list items for each list one by one is very slow.
Use Method Below.
SPSiteDataQuery
The fastest way (and only way in my opinion) is to use the search engine.
You can do queries like "contenttype:document" to search for document across lists.

Sharepoint lookup field and WebId="

I try to add lookup field in content type. Field has this definition:
<Field ID="{c80e8e3c-7124-4772-a39d-5b69f131d542}"
Name="Site"
Group="Tieto Intranet Columns"
Type="Lookup"
DisplayName="Site"
StaticName="Site"
List="Lists/FavoriteSites"
ShowField="Title"
PrependId="TRUE"
WebId="~sitecollection"
>
FavoriteSites list, which I want reference by this lookup field, exists on the site collection scope. Deployment goes fine, but when I create list based on content type with this lookup it looks like that lookup field is not connected to FavoriteSites list. I add some data into FavoriteSites and than I a try to add something into second list with lookup field on FavoriteSites. Unfortunately drop down select, which should show me data from FavoriteSites list is empty.
When I create new lookup column to FavoriteSites manually everything is OK.
Do anybody have some idea where can be problem in this lookup definition?
UPDATE:
As Rich recommended me, I set log level on Verbose a find this message:
The WebId=~sitecollection and List=Lists/FavoriteSites attributes specified for field {c80e8e3c-7124-4772-a39d-5b69f131d542} in feature {d86c7005-d31d-43ae-b86b-38f28b81072e} could not be found. Set List={39CEC23E-FB28-47B3-BC36-C21780AD1D94}.
I don't understand it because list FavoriteSites exists. FavoriteSites list and also second list with Site field are deployed by one feature on site collection scope.
I can't specify list in lookup by GUID because I don't know the guid in deployment time.
What that log message means is that Lists/FavoriteSites does not exist in either the site collection root site or the site where the feature is being activated (if the latter is a subsite).
If Lists/FavoriteSites is being created by a feature, then make sure that it is activated before your Fields feature. Put the ListInstance element right above your Field element if you have to. But the message is clear: the list does not exist at the time that your custom field is being provisioned to the site collection. And that is why it is not working.
To be clear, the list has to exist at the time that the feature is activated, not just when you create a list instance that will use that field.
P.S. I found this by checking the "documentation" for the Microsoft.SharePoint.SPFieldElement.PerformFixUpIfLookUpField method.
Try changing the list field to the ID of the list e.g. List="{4641f5f2-b358-4805-9d7d-e910d2243fb5}"
I would also recommend using SharePointManager to look at the Field definition of your manually created field and to easily find the blooming guids of lists etc.
I had the same problem. In the end my problem was that you can not declaratively reference a list that is in the rootweb. The ~sitecollection token in the WebId property is not working because it will write the Guid between braces, while SharePoint expects it without braces (explanation can be found on http://martensboarterstun.wordpress.com/2013/06/15/how-to-create-a-list-definition-with-a-lookup-field-declaratively/). I ended up placing the Rootweb ID in my list definition.

Sharepoint: SQL to find all documents created/edited by a user

I am looking for a query that will work on Sharepoint 2003 to show me all the documents created/touched by a given userID.
I have found tables with the documents (Docs) and tables for users (UserInfo, UserData)
but the relationship between seems a bit odd - there are 99,000 records in our userdata table, and 12,000 records in userinfo - we have 400 users!
I suppose I was expecting a simple 1 to many relationship with a user table having 400 records and joining that to the documents table, but I see thats not the case.
Any help would be appreciated.
Edit:
Thanks Bjorn,
I have translated that query back to the Sharepoint 2003 structure:
select
d.* from
userinfo u join userdata d
on u.tp_siteid = d.tp_siteid
and
u.tp_id = d.tp_author
where
u.tp_login = 'userid'
and
d.tp_iscurrent = 1
This gets me a list of siteid/listid/tp_id's I'll have to see if I can trace those back to a filename / path.
All: any additional help is still appreciated!
I've never looked at the database in SharePoint 2003, but in 2007 UserInfo is connected to Sites, which means that every user has a row in UserInfo for each site collection (or the equivalent 2003 concept). So to identify what a user does you need both the site id and the user's id within that site. In 2007, I would begin with something like this:
select d.* from userinfo u
join alluserdata d on u.tp_siteid = d.tp_siteid
and u.tp_id = d.tp_author
where u.tp_login = '[username]'
and d.tp_iscurrentversion = 1
Update: As others write here, it is not recommended to go directly into the SharePoint database, but I would say use your head and be careful. Updates are an all-caps no-no, but selects depends on the context.
DO NOT QUERY THE SHAREPOINT DATABASE DIRECTLY!
I wonder if I made that clear enough? :)
You really need to look at the object model available in C#, you will need to get an SPSite instance for a SiteCollection, and then iterate over the SPList instances that belong to the SPSite and the SPWeb objects.
Once you have the SPList object, you will need to call GetListItems using a query that filters for the user you want.
That is the supported way of doing what you want.
You should never go to the database directly as SharePoint isn't designed for that at all and there is no guarantee (actually, there's a specific warning) that the structure of the database will be the same between versions and upgrades, and additionally when content is spread over several content databases in a farm there is no guarantee that a query that runs on one content database will do what you expect on another content database.
When you look at the object model for iteration, also note that you will need to dispose() the SPSite and SPWeb objects that you create.
Oh, and yes you may have 400 users, but I would bet that you have 30 sites. The information is repeated in the database per site... 30 x 400 = 12,000 entries in the database.
If you are going to use that query in Sharepoint you should know that creating views on the content database or quering directly against the database seems to be a big No-No. A workaround could be some custom code that iterates through the object model and writes the results to your own database. This could either be timer based or based on an eventtrigger.
You really shouldn't be doing SELECTs with Locks either i.e. adding WITH (NOLOCK) to your queries. Some parts of the system are very timeout sensitive and if you start introducing locks that the system wasn't expecting you can see the system freak out.
But really, you should be doing this via the object model. Mess around with something like IronPython and experimentations with the OM are almost downright pleasant.

Resources