Getting the SPWeb for a SPAuditEntry - sharepoint

I'm currently building an app that will parse all of the Audit entries in a site collection and send out a pretty email to users.
My problem is that the emails should be based on a particular web (essentially an email summarizing the changes that happened to each subsite). Apparently, there is no information in the SPAuditEntry object about the web it came from except for the DocLocation property.
This means I can get any of the following DocLocations (ItemType = Document, Event = Update):
sites/MySiteCollection/Documents/This is a test.doc
sites/MySiteCollection/Reporting Templates/audit.xml
sites/MySiteCollection/Lists/Reporting Metadata/1_.000
sites/MySiteCollection/MySubSite1/Lists/Announcements/2_.000
sites/MySiteCollection/MySubSite1/Template Documents/SampleTestEmail.doc
I'm thinking I can probably figure out the web from the URL by using SPSite.AllWebs.Names if I have to.
Q: How do I figure out which SPWeb a particular SPAuditEntry comes from?

I might have something (very crude), but it kinda depends on how deep your sub webs are nested. Are they just 1 level deep (i.e. site/web1, site/web2 or site/web1/web1_1 etc.). And have you looked if the SPAuditEntry objects have a ScopeId in their EventData xml? Found an article that describes kinda the same as you that uses the ScopeId from the EventData xml to do some matching:
Article
Also, the following post describes using the ItemId (guid) in an SPSiteDataQuery to retrieve the item, then uses the resulting data (WebId and ListId) to open a specific web / list. Might be a bit inefficient to retrieve an item at a time but it something...
Post

My solution is outlined below in pseudocode:
Get the collection of all web names in my site collection: _allWebNames = site.AllWebs.Names;
Since I only care about the top level SPWeb's inside the site, I parse the SPAuditEntry.DocLocation to get the possible web name. (Ex: will return "MySubSite1" out of "sites/MySiteCollection/MySubSite1/Lists/Announcements/2_.000")
string webName = GetPossibleWebName(SERVER_RELATIVE_URL, docLocation);
Then search my array to see if the web name matches.
index = Array.BinarySearch<string>(_allWebNames, webName, new ServiceSiteNameComparer());
If I find a match, then I can using SPSite.OpenWeb(string) to open the web and get the ID.

Related

In Sharepoint, how do I update a task directly from a link in an email?

I'm just starting to use sharepoint designer and realised there's a lot that can be done to extend the basic features in sharepoint. We have an email alert sent out when a new task is created (by the user) and I want to customise the email so that it also includes a link called 'Assign'. When clicked, I want this link to automatically update the task with the assigned to field for the person that clicked it.
So I think the way to do this would be to hard-code the assign to value in the url behind this link, but I have no idea if this is possible or if there is an easier/better way to do this.
Any advice would be appreciated as I'm a complete beginner.
thanks.
I will not cover "How to modify the contents of an eamil alert" here as that is a seperate question and there are a lot of articles that cover that already.
For the Assigned link :-
You would need to create a custom page (or web part on an existing page) as the destination of your Assign link - this would take the Task ID as a query string param and then update the assigned to with the current user.
You could make this flexible by also taking the ListID but you may want to think about how this could be abused and put appropriate measures in place.
EDIT - in response to comment.
This is top of my head, not checked in compiler. This would have to sit on the same server as SharePoint to work as its using the OM - if you want to use a different server (why would you though) then look in the web services.
private void updateAssignedTo(Guid listId, int itemID)
{
SPWeb web = SPContent.Current.Web();
SPList list = web.Lists[listId];
SPListItem item = list.GetItemById(itemID);
item["Assigned To"] = web.CurrentUser;
item.Update();
}
You're going to have to work out how to get this code into to page or web part (SharePoint Designer is not going to cut it I think, you need Visual Studio) but its a starting point.

create an eventreceiver for logging changes made by users in lists

I'm working on a SharePoint publishing site and I want to "log" all the changes made by users in a SharePoint list.
Some searches on the web guided me to the EventReceiver.
But my EventReceiver must be generic and attached to all lists in the site collection. The "log list" has several columns like the name of the list in which the event occurred, the name of the modified item, its old value and its new value.
Can someone guides me on how to achieve this?
There's already a provided answer for you on StackOverflow, hurrayy!!
It sounds possible. Create a class that inherits from SPItemEventReceiver and override ItemUpdating. You can use the following code to get the list:
using (SPWeb web = properties.OpenWeb())
{
SPList list = web.Lists[properties.ListId];
}
You can then use list to grab the list's title and URL. Next, compare each DictionaryEntry entry in properties.AfterProperties to the corresponding value in properties.ListItem to get your differences. Then save it to your log list. The trick would be automatically attaching your Event Receiver to each newly created list. Perhaps a timer job would work.
That said...
Before trying any of that, go to your site collection's Site Settings. Under Site Collection Administration, click Site collection audit settings. Under Specify the Document and Item events to audit, check Editing items. Only go with a custom solution if that does not give you what you need.
Would Version history not achieve the same functionality?
You can see what fields were changed by who and when. Though you would have to look at a list by list basis.
You can also access the version history information via the object model if you want to generate reports web part.
Otherwise using Janis Veinbergs link on how to attach a event handler to all lists and Rich Bennema method of getting the values from the updated item in a generic way, though I would use ItemUpdated as you don’t want to change the data that was updated only copy it to another location so there is no need to catch the data before it is submitted to the SharePoint database

Problem finding Item List Id in WSS 3.0

I'm having a hard time figuring out how to refer to a specific Item List within a list in SharePoint. I looked up the page in SharePoint Designer and found that the listitem is inside a custom made webpart inside a custom made webpage. I'm coding an event receiver and need to read the information that the user types into that listitem which is a textbox. Does anyone know the code to do this or how to get the guid for the specific list item?
I would appreciate any help I can get. I have tried looking all over the web for the answer. Thanks.
It might be a good idea to edit your question with exactly what you'd like to do with the information you read. However from what you've said so far:
The ID of the item being edited will already be passed through to the event receiver via SPItemEventProperties so there is no need to look it up. If you need to look up a different item in the list (or indeed in a different list altogether), the Accessing list items using the object model page on SharePoint Dev Wiki gives you all of the options. A good general rule is use SPQuery to get best performance on the whole.
Note: There is a pretty good page on the SharePoint Dev Wiki demonstrating how to write an event receiver. It shows how to query and obtain a list item title.
Update after comments:
Once you have an SPListItem object, you can find its GUID through the UniqueId property. In the "Accessing lists" wiki link I've provided above the code samples show how to use the Title property.
Every piece of data you need to access within SharePoint should be available through the object model. This is a simplification, but generally the pages themselves are rendered from template files on the server and combined with data in the database to display to the user. So editing the page programmatically or through its source isn't going to work.
Apologies if I'm making an incorrect assumption but you sound fairly new to SharePoint development. I strongly recommend you read at least the first few chapters of Inside Windows SharePoint Services 3.0 as the inner workings of SharePoint are important to get a good understanding of and this book should help a lot. There is a section of event receivers in it as well.
Have you looked at SharePoint.ListsService Webservice?
string url = "WSS Site URL";
SharePoint.ListsService.Lists lists = SharePoint.ListsService.Lists(url);
XmlNode list = lists.GetList("ListName");
XmlNode xlists = lists.GetListCollection();

How did I get multiple lists with the same name in my SharePoint site?

I have a SharePoint site that's being created from a custom site definition. The site definition has the following Features:
A custom content type.
A custom list template whose schema.xml file refers to that content type.
A list instance feature which refers to my above list template feature.
During the site provisioning process, I activate each of these features (each is at the SPWeb level) through C# code in the order above. My resulting site looks as I expect and seems to work fine, but it has the weird artifact that the "all site content" page for my site shows my custom list twice.
My list acts okay -- its item receivers fire correctly and only once. In SharePoint Manager (SPM), I also see the list show up twice, and when I expand the tree to look at the attributes, they appear identical across the two lists (even the list items inside the lists). I suspect that I may be fooling myself and SPM might be just looking at the same list twice, while some actual rogue list lies in the dark shadows of my site.
So, what could have gone wrong here? How could I have created multiple lists of the same name? How can I correctly create this list? And how can I properly clean up the weirdness in existing sites that exhibit this behavior?
Edit:
In response to Michael Stum's question, I created this console app to loop through the site's lists and get the ID:
using (SPSite site = new SPSite("http://myserver/projects/myproject"))
{
using (SPWeb web = site.OpenWeb())
{
var lists = web.Lists;
foreach (SPList list in lists)
{
Console.WriteLine(list.ID + ": " + list.Title);
}
}
}
This code shows my list twice -- same title, same ID.
Another edit:
I looked in the SharePoint content database for this site, and I executed this query:
SELECT * FROM AllLists where tp_webid = '<my SPWeb guid>'
This reveals that there's only one actual list with the title and GUID that I retrieved from my C# code above. So what is causing these multiple entries to show up when I'm browsing through my site?
I've come across with this issue several times. It's not a bug, most likely you have semantic errors in the elements.xml of your list template.
If a list definition contains more than one default view, the symptoms you described above will show up. Check the elements.xml file of your list template and make sure you don't have more than one View-Element with in it.
Kind regards
Ramon
I suggest you put a call in to Microsoft, this sounds like a bug.
P.S. without seeing the actual solution that creates the list we can't determine what's happening, perhaps a feature got activated twice...
Today I came across this issue and after reading the above answers I came up with an easy solution. Just create a new Default view and the Document library will show up normally again.
Kind regards,
Thijmen Groenewegen
P.s
I "created" the same two libraries by migrating the library from one place to another. At the old place the library was only showed once. If I look at the default views on that library two views are checked as Default.
Groenewegen is spot on.
I ended up with two Announcements lists on a site after I ran Export-SPWeb on a subsite and then Import-SPWeb to move it to a new site collection.
To fix it, I created a new default view for the list, All List Items, selected one of the two All Items views and deleted it, and the issue was fixed.
The Announcements list was being displayed twice on the View All Site Content page, and the data was being shown twice when viewing the All Items page.
Also, an intermediate step that you have to take before creating a new default view, is to open the list or library and add "?contents=1" to the URL so you can open the web part maintenance page and "Close" one of the duplicates. You have to do this because the web part ribbon will not show up on the Announcements page if multiple web parts exist, and you need the ribbon to access the view drop down and create a new view.
Have you tried with:
list.RootFolder.Name
(which shows the "internal" name - a part of the url)
list.Title shows the displayname (which can appear twice or more).
This could also be the explanation why you get multiple lists. You have maybe added them with the same displayname but dirrerent "internal" names?

Showing the list view web part for a list in another site

I cannot show the content of a document library using a list view contained in a web part located on my root web application.
Here is the site structure:
main_site
subsite1
Shared Documents
subsite2
Shared Documents
My webpart is located on the main_site.
In this webpart, I have a Sharepoint ListViewWebPart in which I want to show the Shared Documents from subsite1 for instance, but it does not seem to work. I get the following error:
List does not exist
The page you selected contains a list
that does not exist. It may have been
deleted by another user.
What is odd is that when I debug, I can see that the SPList is correctly initialized and contains the element of my list. However at the line Controls.Add(mylistview), is where the error occurs.
Here is the code I use to bind the list to my ListView:
SPList list = SPContext.Current.Site.AllWebs["subsite1"].Lists["Shared Documents"];
ListView lv = new ListView();
lv.ListId = list.ID.ToString();
lv.ViewId = list.DefaultView.ID.ToString();
lv.DataBind();
this.Controls.Add(lv);
Does someone have a logical explaination and solution to this problem?
The problem is that the list is in another site.
It is possible to use the ListViewWebPart to reference a list from another site in the same site collection. You need to use the WebId property to do this. Here is a code example.
Another option is to use SharePoint Designer to create a Data View Web Part. This will allow you to use a list from another site or the SharePoint web serivces to pull data in. The results look similar to the list view web part and there is some powerful functionality you can use. This is the first blog post I found that demonstrates this, there should be several others.
Finally, you could use the Content Query Web Part. You probably know this one already and it is really more for displaying and not manipulating data.
Edited to remove incorrect information.

Resources