Introduction: the requirements
A customer of ours wanted a website which could manage the integration of just about any external content (meaning video, audio, images, but also Google docs, slides from Slideshare and books from Scribd) in a ‘Resource’ content type. There are multiple ways to do this in Drupal, however there are lots of possible pitfalls.
The possible solutions
I investigated and looked at the following solutions:
- The Embedded Media Field module: the module creates CCK field types that allow you to add EITHER video, audio or image from different content providers. The module has the following problems however:
- It creates 3 CCK field types: Embedded Audio Field, Embedded Video Field and Embedded Image Field. There is a patch here that creates an Embedded generic field which supports all media types, however the patch didn’t work in my case.
- You can “only” embed audio, video and images, so if you want to embed more (like Slideshare or Google Docs content), you will have to find another solution.
- Each time you want to add a new provider, if it’s not already provided as a Drupal module, you have to write a small module.
- The Media module will be THE media embedding solution in the future, however, at the time of writing this article, it is still unstable and under heavy development.
- Finally, the last solution that came to my mind was to allow users to simply embed some HTML code within a Resource. They would simply go to their YouTube video or Slideshare slides or whatever and copy and paste the embed code provided by the website, and all done.
Security pitfall: what NOT to do
It would be very tempting for someone who doesn’t know about Cross site scripting to simply allow his users to use “Full HTML” within their posts. That would allow your users to embed about anything however they want to embed it, without further configuration needed. However, for obvious reasons if you know about cross site scripting issues, you do not want to allow that, and you want to find a more secure way of doing it.
In order to do it securely, you will basically need one single module: Embed filter. This module filters various embed tags (embed, object and script) based on a hostname, so for example you can say that you allow your users to embed anything that comes from youtube.com, but you won’t allow them to embed from any other website. This solves the cross site scripting issues while still allowing your users to embed just about anything.
If you want to configure it in the same way that I’m going to show you in the following lines, you will also need the Better Formats module.
How to configure it ?
First, you obviously need to create a ‘Resource’ content type. Allow your resource to have a Title and a Description.
Then, in your resource content type, create a text field labeled Embed HTML for example.
Then, you will need to create a new Input format. Site configuration > Input formats > Add input format. I called mine Filtered HTML with embed. When you configure it, make sure you activate the Object and embed tag filter which should be present if you have the Embed filter module activated. Also, when you configure it, make sure you allow the <object>, <script>, <embed> and <param> tags in the configuration of the HTML filter.
Then, you will need to allow your users to use this new format. Once you have done this, you will see that your users will be prompted to choose between the Filtered HTML format or the Filtered HTML with embed format. What you probably want is to remove this prompt, and allow the Filtered HTML with embed for the Embed HTML CCK field you created, but only allow the Filtered HTML format for the other fields (like the Description of the resource for example). This is where the Better Formats module kicks in.
Go to Input Formats and in Settings, check “Control formats per node type”. Then, you will need to apply this patch to the Better Formats module. Then go to your Modules list and activate the “Better Formats additional CCK text widgets” module. Go back to your resource content type and edit the ‘Embed HTML’ field you created. Click on ‘Change basic information’ and choose ‘Text field using Better Formats module’ as the Widget type. In the configuration of the field, you should now see an ‘Input format settings’ collapsible box. Only allow the ‘Filtered HTML with embed’ in the list of allowed formats.
Finally, in order to remove those collapsible boxes that allow users to choose their input format, go to the User permissions list and, in the ‘better_formats module’, uncheck the permission to ‘collapsible format selection’.
Configuring the embed filter module
Finally, you will need to configure the embed filter module. Go to Site configuration > Embed filter and add whatever allowed hosts you want to allow in the list. Be careful as, sometimes, some providers do not host their content at the same address as their site. For example, if you want to allow Slideshare, you need to add slidesharecdn.com in your allowed hosts instead of slideshare.com.
Also note that if you want to allow img tags or iframe tags (Google uses iframes to embed their presentations and google docs), you will need to apply this patch to the embed filter module.
Conclusion: or help Media…
You can either do what’s explained in this article, or help the development of the Media module, because everything I wrote in this article will become obsolete when the Media module becomes stable. So waiting and helping the development of the Media module can also be a good option…
A customer wanted a website with some event management that would include:
- A public, general calendar with all of the events
- A per-group calendar for each group of users that would display the group events
- The possibility for group members to create private events, accessible only to the other group members
- A per-user calendar that would display the events created by a specific user
- The possibility for users to create private events, that would be displayed only in their calendar and not viewable by any other user
I believe this set-up can be quite common for any relatively large social website, but I didn’t find any extensive documentation for it.
What NOT to do: the event and OG Calendar module
At first, I thought about installing the Event module, along with the OG Calendar module for the per-group calendars and the Calendar module for the per-user and public calendars. Turns out this is a bad idea, and there are many reasons why:
- The Calendar and Event modules don’t go together: Calendar is based on Views, while Event isn’t. Even when using Event Views, the Calendar module can not display events coming from the Event module (or I missed something, which is possible).
- The Calendar and Event modules have two different ways of displaying their calendar, which would be double work for the designer if you were to use both modules
- The OG Calendar module is no longer being maintained
Here is the list of modules I needed to realize the setup:
- CCK: obviously needed, to create a node of type Event, you should already have it installed
- Views: required by Calendar, you should already have it installed
- Organic groups: this should be part of your installation as well, if you need a per-group calendar
- Private: to allow users to create private events
Understanding Calendar and first steps
The Calendar module is smart: it uses a custom content type that you have to create (you can call it ‘event’) to display events in a calendar display. It basically adds the ‘Calendar’ style to the Views module. So basically, what you have to do is to create a content type to manage your events (which should include a date field, obviously), and then create a view to display the events.
Sean Effel, from Drupaltherapy, shows the detailed steps on how to achieve this in his screencast. Just follow the link and watch the video.
Setting up a per-group calendar
What Sean doesn’t show in his screencast however, is how to set up a per-group and a per-user calendar. If you followed the video, you should now have a public/general calendar showing all of your events.
Creating some test data
In your Drupal installation, create 4 events entitled: ‘Private user event’, ‘Public user event’, ‘Private group event’, ‘Public group event’. The idea is that, at the end of this article, you should have a public calendar displaying the ‘Public user event’ and ‘Public group event’, a group calendar displaying (when you are logged in as a group member) the ‘Public group event’ and ‘Private group event’ and finally a user calendar displaying (when you are logged in as the user who created the ‘Private user event’) the ‘Private user event’ and ‘Public user event’.
Setting up Organic Groups
If you want to have private group events, you simply have to check “Visibility chosen by author/editor …” under “Visibility of posts” in “Organic groups access configuration”. This will allow the event author to create private group events, visible only by group members.
Setting up the per-group calendar view
Go to Site building > Views > List. Select your general calendar view (which should be called calendar) and click on Clone. As View name, use ‘calendar_og’, enter a description such as ‘per-group calendar view’ and click Next.
Now I had a problem which seems to me like a bug: after you cloned the view, if you try to get a Preview of the “Calendar page” display, you will only get the Navigation bars. In order to change this, change the style plugin to “Calendar” in “Defaults”, AS WELL AS in “Year view”, “Month view”, “Day view” and “Week view”.
Then, you will need to change the Path of this new view. Select “Calendar page” > Page settings > Path and change it to ‘node/%/calendar’. Also, if you wish, set the Menu to “Menu tab” and entitle it “Calendar”.
You now need to add an argument to the view in order to tell it from which group it should retrieve the events. Add an argument of the type “Organic groups: Groups”, select “Provide default argument” and “Node ID from URL”. You can also select a “Group nodes” validator if you wish. DON’T FORGET, after you added this argument, to organize it so that the FIRST argument is the “Organic groups: Groups” one, and the second is the date argument, otherwise the view will not work.
If you go to a group page, you should now have a tab saying “Calendar” or, if you didn’t set a Menu tab, you can navigate to http://urlofyoursite/node/%gid%/calendar, and you should see a calendar displaying only the events of the group identified by the id given in the URL.
Edit the ‘Private group event’ you created earlier and make it private, using the “Organic groups” option, and it should not appear in the group calendar, unless you are logged in as a group member.
Setting up a per-user calendar
Almost the same steps can be followed in order to set up a per-user calendar, you simply have to change a few things:
- Change the name of the cloned view to something like ‘calendar_my’ or ‘calendar_user’
- Change the path of the Calendar page to ‘user/%/calendar’
- Change the “Organic groups: Groups” argument to a “User: Uid” argument and in the “Provide default argument” select “User ID from URL”. Don’t forget, once again, to put the argument first in the list
At the end of these steps, you should be able to see a calendar when you navigate to http://urlofyoursite/user/%uid%/calendar, showing only the events created by the user identified by %uid%.
User private events
In order to allow users to create private events (ie accessible by themselves only), I used a very simple module: Private. There might be some other modules that can do the same thing and more, but Private simply does the job. It allows you to let your users say whether they want a specific node to be private or not. Once the module is installed, edit the ‘event’ content type you created and, under ‘Workflow settings’, set the ‘Privacy’ option to ‘Enabled (public by default)’. This will enable a checkbox in the event creation form, allowing your users to define an event as private.
Go back to the ‘Private user event’ you created earlier and make it private. It should now only show in your per-user calendar if you are connected as the author of the event.
Conclusion: views power
Views is a very powerful module and the idea of using it through the Calendar module is great. Given that your event content type is a simple node, you can also easily add it some more things, such as geolocalization using the GMap + Location module.