views:

350

answers:

3

WSS 3.0 will let me send an email to a group when a new task is added to a task list. What I would like to do is to run a weekly task that sends out reminders of tasks due within certain periods, i.e. 2 days, 7 days, 14 days etc. I thought the simplest way would be to build a little C# app thatr sits on the WS2K3 box and qeuries the WSS database. Any ideas on which tables I should be checking? More generally is there an overall schema for the WSS3 database system?

If anyone is aware of an existing solution with code please let me know.

Thx++

Jerry

+1  A: 

Don't bother trying to go directly to the database. You will have a very hard time because it's undocumented, unsupported, and not recommended. SharePoint does in fact have a full featured object model though.

If you reference Microsoft.SharePoint.dll (located in the Global Assembly Cache of a machine with SharePoint installed on it) you can access the data that way. The objects you'll want to start with are SPSite, SPWeb, SPList, SPQuery, and SPListItem. All of which you can find very easily on http://msdn.microsoft.com in a search.

Another less-flexible but code-free possibility you could try is creating several different views that include upcoming tasks then via the GUI set up an alert for when items are added to that view.

Josh Einstein
Josh,Many thanks, appreciate the advice re direct DB access.
G Forty
+2  A: 

Any time you need something in sharepoint that is executed periodically, 99 times out of a 100 you'll need to build a TimerJob. These are scheduled tasks that run inside SharePoint and you can create your own, then using a feature + featurereceiver to actually "install" the timoerjob (definition) and assign it a schedule.

For more info: see Andrew Connell's article on TimerJobs.

P.S. Never query /update the databases related to SharePoint directly! This will make you "unsupported", i.e. if anything happens microsoft will charge (a lot of) money to come and fix it, instead of being able to ask for regular support. (if you are say an MSDN subscriber you get up to 4 free support calls a year).

Colin
+2  A: 

My suggestions:

  • don't create a console app, create a class that inherits from SPJobDefinition.
  • set SPJobLockType.Job to this timer, this will grant that the job is executed only once in the whole farm, even if you are running multiple front-end servers
  • in the, timer job, open the SPSite, SPWeb objects you need, then find the SPList\
  • Using SPQuery filter out only the items you need - I believe, you will have to filter out the ones where Status!=Complete
  • Loop through the results collection (which will be of type SPListItemCollection, apply your rules, checking the DueDate and Datetime.Now, send the e-mails
  • Since a task is simply a SPListItem, it has a Properties property, which is actually a property bag - you can add whatever properties you need. So, add a property My_LastSentReminderDate. Use this property to check if you are not sending too much of "corporate spam" :-)
  • To install your SPJobDefinition in a SharePoint farm, you can use a PowerShell script. I can give you examples, if needed.

Don't forget to Threading.Thread.CurrentThread.CurrentCulture = Your_SPWeb_Instance.Locale, otherwise date comparisons may not work if the web has a different locale!

EDIT: This is how a typical reminder looks like in my applications:

Public Class TypicalTimer
    Inherits SPJobDefinition

    Public Sub New(ByVal spJobName As String, ByVal opApplication As SPWebApplication)
        'this way we can explicitly specify we need to lock the JOB
        MyBase.New(spJobName, opApplication, Nothing, SPJobLockType.Job)
    End Sub

    Public Overrides Sub Execute(ByVal opGuid As System.Guid)
        'whatever functionality is there in the base class...
        MyBase.Execute(Guid.Empty)
        Try
            Using oSite As SPSite = New SPSite("http://yourserver/sites/yoursite/subsite")
                Using oWeb As SPWeb = oSite.OpenWeb()
                    Threading.Thread.CurrentThread.CurrentCulture = oWeb.Locale
                    'find the task list and read the "suspects"
                    Dim oTasks As SPList = oWeb.Lists("YourTaskListTitle")
                    Dim oQuery As New SPQuery()
                    oQuery.Query = "<Where><Neq><FieldRef Name='Status'/>" & _
                                    "<Value Type='Choice'>Complete</Value></Neq></Where>"
                    Dim oUndoneTasks As SPListItemCollection = oTasks.GetItems(oQuery)

                    'extra filtering of the suspects.
                    'this can also be done in the query, but I don't know your rules
                    For Each oUndoneTask As SPListItem In oUndoneTasks
                        If oUndoneTask(SPBuiltInFieldId.TaskDueDate) IsNot Nothing AndAlso _
                            CDate(oUndoneTask(SPBuiltInFieldId.TaskDueDate)) < Now().Date Then
                            ' this is where you send the mail
                        End If
                    Next
                End Using
            End Using
        Catch ex As Exception
            MyErrorHelper.LogMessage(ex)
        End Try
    End Sub
End Class

To register a timer job, I typically use this kind of a script:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Administration")
[System.Reflection.Assembly]::LoadWithPartialName("Your.Assembly.Name.Here")
$spsite= [Microsoft.SharePoint.SPSite]("http://yourserver/sites/yoursite/subsite")

$params = [System.String]("This text shows up in your timer job list (in Central Admin)", $spsite.WebApplication
$newTaskLoggerJob = new-object -type Your.Namespace.TypicalTimer -argumentList $params

$schedule = new-object Microsoft.SharePoint.SPDailySchedule
$schedule.BeginHour = 8
$schedule.BeginMinute = 0
$schedule.BeginSecond = 0
$schedule.EndHour = 8
$schedule.EndMinute = 59
$schedule.EndSecond = 59

$newTaskLoggerJob.Schedule = $schedule
$newTaskLoggerJob.Update()
naivists
N. Nice. Thanks. Appreciate the detail. Any examples welcomed, even if PowerShell, however I am using a single dedicated W2K3 server in this case.
G Forty
Added some code examples.
naivists
N. Very nice. My thanks - this is most helpful.
G Forty
The "best-practices" way of registering TimerJobs is by creating a feature + featurereceiver, and I usually add an Admin page (visible in the Central Admin site) for changing the job's schedule.
Colin