Searchable civiEvents in drupal7 - search

I have a site that is running on drupal 7 and uses civicrm 4.4.1. I need the events to be included in the search results.
So far all I have found was dated documentation on civicrm that required modules that are not available for Drupal 7.
I also tried the search page module and it is not grabbing the events.

It's a little unclear what you're looking for, so I'll answer two ways.
You can search for event participants most easily by going into the Search menu and selecting Advanced Search. You can see the events information by clicking on the Events header--the section will open up. You don't need to enter anything else on the search form unless you want to search for that too (i.e. fundraiser attendees who live in West Virginia).
If you want CiviCRM events to show up in your Drupal content search results, you'll need to get the events to appear as content. CiviCRM information is 100% separate from Drupal content, but you may have some luck using the CiviCRM Entity module https://drupal.org/project/civicrm_entity to expose CiviCRM events as entities.

I haven't seen anything pre-built that will include CiviCRM events in the standard Drupal site search. Looking at the search api, I think it is possible to create a module to do that, but I don't think it is trivial. I haven't written any modules for the search api, but it seems like there is a bit of bookkeeping to be done to write this kind of integration.
I've handled this in a couple of ways for my customers. One, create a content type for Events and put a detailed description and basic date information in the content type. When creating events in CiviCRM, just make a barebones event for registration and link to the event registration page directly from the event node. Two, make event search a separate action, with a nice link and a view.
I know that neither of these solutions is ideal, but I don't see a quick solution apart from writing your own search plugin.

We create content in Drupal and link it to Civi event pages using a Computed Field that matches Event Name to the node's Title field, and Event Start Date to the node's Event Date field. Sample code for the Computed Field:
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
$query = "SELECT
ce.id
FROM {node} n
INNER JOIN {field_data_field_event_date} de ON n.nid = de.entity_id AND n.vid = de.revision_id
INNER JOIN {civicrm_event} ce ON n.title = ce.title COLLATE utf8_unicode_ci
AND ce.start_date = convert_tz(field_event_date_value,'GMT','America/New_York')
WHERE n.nid = :nid
AND n.vid = :vid
LIMIT 1";
$result = db_query($query,
array(':vid' => $vid, ':nid' => $id))->fetchField(0);
if ($result === NULL || $result == "")
{
$entity_field[0]['value'] = 0;
}
else
{
$entity_field[0]['value'] = $result;
}
Then you can use a bit of display code like this:
if ($entity_field_item['value'] == 0)
{
$display_output = '';
}
else
{
$display_output = 'Buy tickets';
}
Since we have the Civi event code saved to the node, we can also use any native Drupal search or Views functionality, and get creative in Drupal templates as needed. Other options could be to write your own module that does something like this, or consider using the Civi REST endpoint /sites/all/modules/civicrm/extern/rest.php?entity=Event&action=getlist&json={"sequential":1}&api_key=yoursitekey&key=yourkey with Drupal Feeds and Feeds Extensible Parsers modules for a solution that creates and updates the Drupal events with minimal code required.

Related

SharePoint My Sites Social Comment in multiple languages

I'm trying to create custom post to current user newsfeed in SharePoint 2013 Newsfeed. I must create posts in different languages like OTB functionality.
So I have something like this:
SocialDataItem docLink = new SocialDataItem
{
ItemType = SocialDataItemType.Document,
Text = "link to a document",
Uri = docLinkUrl
};
SocialPostCreationData postCreationData = new SocialPostCreationData();
postCreationData.ContentText = "Check this out {0}.";
postCreationData.ContentItems = new SocialDataItem[1] {
docLink
};
I would like "Check this out" to be read from resource file or something like that. The same functionality is with OTB. If a user starts to follow a site this is added to his news feed and if you change current language the text is changed.
Example:
English language:
George is now following project.
Slovenian language:
George zdaj spremlja mesto »project«.
Is this even possible with a custom code?
Thanks for all your replies.
It looks like you are trying to create a newsfeed post with custom code, maybe by using a button on an ASPX form. Anything will be possible with your custom code, so yes you could post to the users' feed in any language and yes you can use resource files to achieve this.
The newsfeed posts itself will only be in one language though and can never be in multiple languages.
The posts are actually stored in a Microfeed list within the users' personal site as list items. There is no possibility to store multiple versions (i.e. languages) of said list items in that list and hence you cannot have the same newsfeed post appear in multiple languages.
This would only be possible with quite complicated custom code: If for example you would create your own Newsfeed webpart which displays the regular newsfeed entries and additionally translated posts from another special custom list. Very complicated.
As for resource files you can follow any localization tutorial on localizing such as: Walkthrough: Localizing a Web Part. The correct localization will automatically be loaded by the current users' culture. This way you could post to the users feed in his/her language. Other users will also see that exact same post in the same language.

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.

Getting the SPWeb for a SPAuditEntry

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.

How to enable "Connect to Outlook" function in your custom list?

How can I enable the functionality to sync my custom list with Outlook 2007 todo or calendar list? I assume it's possible with custom lists too, but I cannot find any documentation on it.
To my knowledge this is not possible. If you need to sync a todo list, create a task list. Then you can delete all the columns that don't interest you, and add whatever columns you want to use.
The same goes for calendar, if you want a list syncronised with your outlook calendar, then create a calendar list and customize it to your needs.
To expand upon Filip's great answer . . .
According to this MSDN post, the custom list template has a different type designation (100) than the Task Template (106 in the article above, 107 in my research of SP2010). This is what the UI looks at to disable the Outlook Sync button. So, if your custom list is based on a custom content type you created then you can recreate your list to be Outlook compatible.
If your list already contains data, export it to Excel
Create a new list based on the Task template (instead of Custom)
Add your CT and delete the Task CT (if your content type is based on the Task CT i.e. has the columns) and any others your list doesn't need
Add any other columns your list needs but may not be part of your CT (or if you don't use a custom CT)
Use Datasheet view to copy and paste your data into the new list (observe column order)
Caveats: Not all data columns can be copied using this method (e.g. Attachments, system fields, etc.)
Hope this helps clarify
This is available / possible (well it takes some programming to achieve it) - see here.
For my solution, I aggregate data between sites and sync them with outlook. There are some tricky things like to map item's uniqueId to integer ID (probably a database table with mappings) to refer to specific item correctly, but it's not impossible.
But it's not something you can use right away - coding required. However if you really, really need it, then it's a some-way to go.
If your custom list is based off of a sharepoint list, then you can connect it to outlook by generating a link formatted based off the stssync protocol.
I created a custom list definition based off the events (Calendar) list.
It uses the base calendar list template plus some custom fields and forms.
I created a link formatted in accordance with the stssync protocol, and successfully connected it with outlook:
stssync://sts/?ver=1.1&type=calendar&cmd=add-folder&base-url=[site url]&list-url=[your list url]&guid=[GUID of list]&site-name=[SiteName]&list-name=[ListName]
Yeah not possible sadly. Also, if you create custom columns in a task list or calender, Outlook won't sync those columns.
I have been struggling with the same issue and found that it cannot be done with the built in functionality that SharePoint has, but there is a 3rd party program that allows this to be done. You can try with ProperSync. It will allow you to connect the custom fields of a custom list from SharePoint and view and edit them using Outlook.
This is the link to the main site: http://propersync.com/default.aspx
You can override List Ribbon Button, which holds sync logic, and create your custom action on it.
Here is good article about creating ribbons: http://blogs.msdn.com/b/sharepointdeveloperdocs/archive/2009/12/07/sharepointfoundationhowtoaddtabtoribbon.aspx
For List View OutlookSyncButton you should in CommandUIDefinition specify Location="Ribbon.List.Actions.ConnectToClient".
For Calendar View - you should specify Location="Ribbon.Calendar.Calendar.Actions.ConnectToClient".
Now, in CommandUIHandler/CommandAction you specifing JS code that connects to outlook (simply I grab it from SP :)):
alert("Let's go!");
var listid = '{ListId}';
var list;
ExecuteOrDelayUntilScriptLoaded(GetParamsAndSync, 'sp.js');
function GetParamsAndSync()
{
var clientContext = new SP.ClientContext.get_current();
var web = clientContext.get_web();
list = web.get_lists().getById(listid);
clientContext.load(list);
clientContext.load(web);
rf = list.get_rootFolder()
clientContext.load(rf);
clientContext.executeQueryAsync(
function() {
viewUrl=rf.get_serverRelativeUrl();
ExportHailStormOverride('calendar','{SiteUrl}','{ListId}', web.get_title(),list.get_title(),viewUrl,viewUrl,'')
},
function() {alert('Error')});
}
//This function was taken from SharePoint sp.init.js
function ExportHailStormOverride(type,weburl,guid,webname,listname,viewurl,passport,listrooturl,folderurl,folderid)
{ULSA13:;
var strAppName=GetCookie('stsSyncAppName');
var strIconName=GetCookie('stsSyncIconPath');
var maxLinkLength=500;
var maxNameLength=20;
var link='stssync://sts/?ver=1.1'
+'&type='+escapeProperly(type)
+'&cmd=add-folder'
+'&base-url='+escapeForSync(weburl)
+'&list-url='+escapeForSync('/'
+ makeAbsUrl(viewurl).substr(weburl.length+1)+'/')
+'&guid='+escapeProperly(guid);
if (window.self.offlineBtnUser !=undefined)
link+='&user-id='+offlineBtnUser;
var names='&site-name='+escapeForSync(webname)
+'&list-name='+escapeForSync(listname);
var context='';
if (folderurl)
context+='&folder-url='
+ escapeForSync('/'+folderurl.substr(listrooturl.length+1));
if (folderid)
context+='&folder-id='+folderid;
if (link.length+names.length+context.length > maxLinkLength &&
(webname.length > maxNameLength || listname.length > maxNameLength))
{
if (webname.length > maxNameLength)
webname=webname.substring(0, maxNameLength-1)+'...';
if (listname.length > maxNameLength)
listname=listname.substring(0, maxNameLength-1)+'...';
names='&site-name='+escapeForSync(webname)
+'&list-name='+escapeForSync(listname);
}
link=link+names+context;
var L_StssyncTooLong_Text='The name of site or list is too long. Make it shorter.';
if (link.length > maxLinkLength)
alert(L_StssyncTooLong_Text);
else
{
try
{
window.location.href=link;
}
catch (e)
{
alert('Sync error.');
}
}
}

Sharepoint WebParts

Say you have several webparts, one as a controller and several which take information from the controller and act on it. This is fairly easy to model using the Consumer/Producer interface introduced in ASP 2.0.
How would you be able to add interactions the other way around whilst still maintaining the above?
A simple example would be: the user enters information into webpart A which performs a search and the results would be displayed on webpart B. Webpart C allows you to filter the results which should trigger webpart A to re-submit the query and hence update the results in B.
It doesn't seem possible to do in WSS 3.0 because you are only allowed 1 interface to be used in all of the connections at any one time.
Does this even make sense ? :-)
A quick and dirty solution to enable arbitrary control communication is to use recursive find control and events. Have the controls search the control tree by control type for what they need and then subscribe to publicly exposed events on the publishing control.
I have previous used the trick to enable standard server controls to find each other when embedded in CMS systems from different vendors to avoid a specific communication API entirely.
I don't see anything wrong with webpart A getting a reference to webpart B and calling public/internal methods/properties or subscribing handlers to public/internal events. One point of mention when doing this though: EnsureChildControls. I have witnessed with my own eyes one webpart being run clear to PreRender while another webpart hadn't even run CreateChildControls.
From webpart A, fetch your reference to webpart B (in this case webpart B is of type Calendar) like so:
private Calendar _calendarWP = null;
public Calendar CalendarWP
{
get
{
if (_calendarWP != null)
return _calendarWP;
else
foreach (System.Web.UI.WebControls.WebParts.WebPartZone zone in this.WebPartManager.Zones)
foreach (System.Web.UI.WebControls.WebParts.WebPart webpart in zone.WebParts)
if (webpart is Calendar)
{
_calendarWP = (Calendar)webpart;
_calendarWP.EnsureChildControls();
return _calendarWP;
}
return null;
}
}
Now you can do things like fetch some new data and update the Calendar like so:
IEnumerable newData = SomeDataProvider.GetNewData(args);
CalendarWP.someGridView.DataSource = newData;
CalendarWP.someGridView.DataBind();
Or perhaps let webpart A toss a reference to itself over to webpart B so it can use webpart A's public/internal properties to go fetch data for itself:
CalendarWP.UseWPAToFetchData(this);

Resources