How to send Real Meeting Requests from Sharepoint 2010 – Part4 Usage

How to send Real Meeting Requests from Sharepoint 2010 – Part4 Usage:

Here is the links for How to send Real Meeting Request From Sharepoint 2010 Series:
http://blog.bugrapostaci.com/2012/02/17/how-to-send-real-meeting-request-from-sharepoint-2010-part-1/
http://blog.bugrapostaci.com/2012/02/17/how-to-send-real-meeting-request-from-sharepoint-2010-part-2/
http://blog.bugrapostaci.com/2012/02/17/how-to-send-real-meeting-request-from-sharepoint-2010-part-3-deployment/
http://blog.bugrapostaci.com/2012/02/17/how-to-send-real-meeting-requests-from-sharepoint-2010-part4-usage/

1) Open a sharepoint calendar

2) Add new Event

Meeting Requests can only be send through from a Meeting Workspace in this project.So you have to select checkbox of workspace.

3) Create a new Meeting Workspace or Select an existing Meeting WorkSpace

If you have already a created Meeting WorkSpace select that one.

4) The Meeting Workspace home page opens automatically.

5) Add Manage Meeting Requests Web Part  to default page

6) Add needed attendess

7)Return to home page of Meeting Site

8) Send a meeting Request form Manage Meeting Request Web Part

If you able to send a meeting request successfully the gui has changes and information message shown that confirm your Meeting Request has been sent successfully.
There is only 4 feature implemented in this project.

  • Send Meeting Request
  • ReSend Meeting Request
  • Refresh Attendees Status
  • Cancel Meeting

9) Check Your Outlook and Clients for confirmation .

Advertisements

How to send Real Meeting Request From Sharepoint 2010 – Part 2

Hello Everyone ,

How to send Real Meeting Request From Sharepoint 2010 article continues with part2

Here is the links for How to send Real Meeting Request From Sharepoint 2010 Series:
http://blog.bugrapostaci.com/2012/02/17/how-to-send-real-meeting-request-from-sharepoint-2010-part-1/
http://blog.bugrapostaci.com/2012/02/17/how-to-send-real-meeting-request-from-sharepoint-2010-part-2/
http://blog.bugrapostaci.com/2012/02/17/how-to-send-real-meeting-request-from-sharepoint-2010-part-3-deployment/
http://blog.bugrapostaci.com/2012/02/17/how-to-send-real-meeting-requests-from-sharepoint-2010-part4-usage/
Lets have a look for internally whats happening in a Meeting Workspace.

If you open a meeting workspace web with Sharepoint Manager 2010 you can brows all components in a basic meeting workspace template.
Some important list are Attendees , Meeting Serries , Workspace Pages ,

The Meeting Serries list contains Event information when you related a calender item with a meeting workspace instance. In this demo we have already attached two calender event this this meeting workpaced named “Scrum Meetings” . Every item has in Meeting Series an InstanceID so when you open a Event item and click linked workspace url
you can see this instanceID has been added end of this url . For example:
http://blog.bugrapostaci.com/scrummeetings?InstanceID=2

That means sharepoint sperates data according this Instance Parameter. As you noticed if you look carefully above image we have 6 attendees . This number is sum of all attendees count .But when you connect a workspace with an InstanceID  and if you compare fallowing properties for an Attendees list.
SPList attendeesList = web.Lists[“Attendees”];
attendeesList.ItemCount  is 6 : means all attendees count contains other meeting instances counts
attendeesList.Items.Count is 2 : meens this instance attendees count.

Sharepoint is differantiate the attendees data automatically and internally for which meeting workspace instance in use.

So be careful when you are working with in Meeting Workspaces on InstaceID property and differantiation of data according to this property.

Sharepoint Manager 2010 is a very useful tool when you programming with Sharepoint. You can use it with define Column Names and properties for serval objects in hiearchically.

But what if you dont want to use it , the powershell can also makes some help in this issue. For example if you want to learn which internal columns of an Meeting Series List item . you can get this information via powershell and write in a file in your drive like:

$Site = Get-SPList http://blog.bugrapostaci.com
$web = $site.OpenWeb(“ScrumMeetings”)
$mList = $web.Lists[“Meeting Series”]
$mList.Fields |ft title , internalname > c:\MeetingSeriesFields.txt

One advantage of powershell that you can also check values of created properties which SPM2010 does not. For example you may wonder how sharepoint keeps EventURL of an Related Event item:
$Site = Get-SPList http://blog.bugrapostaci.com
$web = $site.OpenWeb(“ScrumMeetings”)
$mList = $web.Lists[“Meeting Series”]
$item = $mList.Items[1];
$item[“EventURL”] and press enter
Results is: [URL], [List Title] -> There is a space char after “,” so you should use trim() function when you parsing this data.
http://blog.bugrapostaci.com/lists/TestCalender, Meeting Calendar

After we complete understanding on Meeting Workspace  now contine with our project

MeetingRequestWebPart -> Page Load
  1. protected void Page_Load(object sender, EventArgs e)
  2. {
  3.     #region GUI operations
  4.     //Some GUI operations
  5.     #endregion
  6.     //This webpart is only usable for Meeting Workspace Sites.
  7.     if (!SPMeeting.IsMeetingWorkspaceWeb(SPContext.Current.Web))
  8.     {
  9.         InformationText.Text = “This webpart is only addable for a Meeting Workspace Web Site”;
  10.         AdminPanel.Visible = false;
  11.         return;
  12.     }
  13.     //Get Current Meeting information
  14.     SPMeeting currentMeeting = SPMeeting.GetMeetingInformation(SPContext.Current.Web);
  15.     MeetingInfo info = MeetingInfo.GetMeetingInfo(currentMeeting);
  16.     //Only the meeting organizer manage meetigs.
  17.     if (!info.OrgnaizerAccount.Equals(SPContext.Current.Web.CurrentUser.LoginName, StringComparison.InvariantCultureIgnoreCase))
  18.     {
  19.         InformationText.Text = “Only Organizer of this meeting \”” + info.OrganizerName + “\” can manage the requests”;
  20.         AdminPanel.Visible = false;
  21.     }
  22.     else
  23.     {
  24.         if (IsAppointmentExists(info.MeetingIdentifier)) //if Meeting request is already sent.
  25.         {
  26.             SavedMeetingInfo = LoadAppointment(info.MeetingIdentifier);
  27.             btnSendMeetingRequest.Visible = false;
  28.             btnReSendMeetingRequest.Visible = true;
  29.             btnCancelMeeting.Visible = true;
  30.             btnRefreshAttendeesStatus.Visible = true;
  31.             if(!_ByPassClearInfo)
  32.                 InformationText.Text = “Meeting requests have been send at” + SavedMeetingInfo.RequestSentDate.ToLongDateString() + ” “ + SavedMeetingInfo.RequestSentDate.ToLongTimeString();
  33.         }
  34.         else // if not sent before
  35.         {
  36.             btnSendMeetingRequest.Visible = true;
  37.             btnReSendMeetingRequest.Visible = false;
  38.             btnCancelMeeting.Visible = false;
  39.             btnRefreshAttendeesStatus.Visible = false;
  40.         }
  41.         //assign button events.
  42.         btnSendMeetingRequest.Click += new EventHandler(btnSendMeetingRequest_Click);
  43.         btnReSendMeetingRequest.Click += new EventHandler(btnReSendMeetingRequest_Click);
  44.         btnCancelMeeting.Click += new EventHandler(btnCancelMeeting_Click);
  45.         btnRefreshAttendeesStatus.Click += new EventHandler(btnRefreshAttendeesStatus_Click);
  46.     }
  47. }


In Page Load,

We are doing some gui operations.
Checking webpart added correct web site template , should be a meeting workspace template
Getting Current and latest meeting information
Checking the owner mean organizer beacuse only orginazer manages meetings.
Prepare GUI according to if meeting is already send or not.
Also we set here the SavedMeetinfo property of control via fallowing line
-> SavedMeetingInfo = LoadAppointment(info.MeetingIdentifier);
MeetingInfo LoadAppointment(string identifer)  helper function brings us the Saved MeetingInfo in previous state from web.Properies bag.
That information is imported because we are storing Exchange Appointment object’s ID in this object.

MeetingRequestWebPart -> Refresh Attendees Status
  1. public void RefreshAttendeesStatus()
  2. {
  3.     if (SavedMeetingInfo == null) return;
  4.     ExchangeServiceConnection conn = new ExchangeServiceConnection(SPContext.Current.Web.CurrentUser);
  5.     SPMeeting currentMeeting = SPMeeting.GetMeetingInformation(SPContext.Current.Web);
  6.     Appointment app = Appointment.Bind(conn.Service, SavedMeetingInfo.AppointmentID);
  7.     Dictionary<string, MeetingResponseType> aStatus = new Dictionary<string, MeetingResponseType>();
  8.     foreach (Attendee att in app.RequiredAttendees)
  9.     {
  10.         if (att.ResponseType != null)
  11.         {
  12.             aStatus.Add(att.Address, (MeetingResponseType)att.ResponseType);
  13.         }
  14.     }
  15.     foreach (Attendee att in app.OptionalAttendees)
  16.     {
  17.         if (att.ResponseType != null)
  18.         {
  19.             aStatus.Add(att.Address, (MeetingResponseType)att.ResponseType);
  20.         }
  21.     }
  22.     RunAsAdmin.Run((site, web) =>
  23.     {
  24.         SPList Attendees = web.Lists[“Attendees”];
  25.         foreach (SPListItem item in Attendees.Items)
  26.         {
  27.             SPUser user = web.EnsureUser(item.Title);
  28.             if (aStatus.ContainsKey(user.Email))
  29.             {
  30.                 MeetingResponseType rtype = aStatus[user.Email];
  31.                 item[“Response”] = ExchangeHelper.ConvertSPMeetingResponse(rtype);
  32.                 item.Update();
  33.             }
  34.         }
  35.     });
  36. }

In refresh attendees function,

We are getting current Meeting information and already created Appointment object. For updating attendees status a meeting request must already be created.
Collecting all Attedees and thier responses in a dictionary (considering performance )
Updating Attendees status in web.Lists[“Attendees”] list . We are converting Response type beacuse Exchange.MeetingResponseType has 6 option but Response (Choice)
Column in attendees list only 4 option that none,Accepted,Declined,Tentative

MeetingRequestWebPart -> Update Meeting Request
  1. public void UpdateMeetingRequest()
  2. {
  3.     if (SavedMeetingInfo == null) return;
  4.     ExchangeServiceConnection conn = new ExchangeServiceConnection(SPContext.Current.Web.CurrentUser);
  5.     SPMeeting currentMeeting = SPMeeting.GetMeetingInformation(SPContext.Current.Web);
  6.     Appointment app = Appointment.Bind(conn.Service, SavedMeetingInfo.AppointmentID);
  7.     MeetingInfo info = MeetingInfo.GetMeetingInfo(currentMeeting);
  8.     ExchangeHelper.UpdateAppointment(app, info);
  9.     //Clear All Attendees
  10.     app.RequiredAttendees.Clear();
  11.     app.OptionalAttendees.Clear();
  12.     //Add Atteendees from Workspace Attendees List.
  13.     AddAttendees(app);
  14.     try
  15.     {
  16.         app.Update(ConflictResolutionMode.AutoResolve);
  17.         info.AppointmentID = SavedMeetingInfo.AppointmentID;
  18.         InfoMessage = “Meeting Request sent successfully”;
  19.     }
  20.     catch (Exception ex)
  21.     {
  22.         ULSLoggingService.LogError(ULSLoggingService.SMR_ERROR, ex.Message + Environment.NewLine + ex.StackTrace);
  23.         InfoMessage = “An Error occured.Please contact your administrator”;
  24.     }
  25.     UpdateAppointment(info);
  26. }

In UpdateMeetingRequest Function ;
First we checking SavedMeetingInfo object is exists.
Creating an exchange connection.
Getting current meeting.
Appointment app = Appointment.Bind(conn.Service, SavedMeetingInfo.AppointmentID); // with this line we are binding already created Appointment object in Exchange. SavedMeetingInfo object contains AppointmentID which i mentioned above.
We are setting old Appointment object with new values by calling ExchangeHelper.UpdateAppointment(app, info);

(Basically we are doing in ExchangeHelper.UpdateAppointment something like below:
app.Subject = info.Title;
app.Start = info.EventDate;
app.End = info.EndDate;
app.Location = info.Location;
…. return app; )
Clearing All Attendeess
Add all attendees again

Update Appointment object that will resend all meeting request again via app.Update() command.
Set AppointmentID to new MeetingInfo class instance.
Update new MeetingInfo class via overriding old MeetingInfoClass (SavedMeetingInfo)

MeetingRequestWebPart -> Cancel Meeting Request
  1. public void CancelMeetingRequest()
  2. {
  3.     if (SavedMeetingInfo == null) return;
  4.     ExchangeServiceConnection conn = new ExchangeServiceConnection(SPContext.Current.Web.CurrentUser);
  5.     SPMeeting currentMeeting = SPMeeting.GetMeetingInformation(SPContext.Current.Web);
  6.     try
  7.     {
  8.         //Get existed appointment.
  9.         Appointment app = Appointment.Bind(conn.Service, SavedMeetingInfo.AppointmentID);
  10.         app.CancelMeeting();
  11.         ClearAppointment(SavedMeetingInfo);
  12.         InfoMessage = “Meeting has been canceled successfully.”;
  13.     }
  14.     catch (Exception ex)
  15.     {
  16.         ULSLoggingService.LogError(ULSLoggingService.SMR_ERROR, ex.Message + Environment.NewLine + ex.StackTrace);
  17.         InfoMessage = “An error occured.Please contact your administrator”;
  18.     }
  19. }

In CancelMeetingRequest function:
Like before we are checking SavedMeetInfo is exists , creating an exchange connection object and getting currentmeeting object.
Appointment app = Appointment.Bind(conn.Service, SavedMeetingInfo.AppointmentID); // with this line we are binding already created Appointment object in Exchange.
And Canceling Meeting via app.CancelMeeting() function.
Clearing previously saved MeetingInfo instance from web.properties.
PS: There is a trick when you try removing a property correctly from SPWeb object .Check the fallowing link:
http://blog.bugrapostaci.com/2012/02/17/clearing-or-removing-a-keyvalue-from-spweb-properties-tipstricks/

Next Article: Part 3 Deployment.

Sharepoint 2010 – Basic Authentication and Php .net web service connection.

A few days ago i have faced a problem that an application which coded with php try to connect sharepoint web services. And it didnt not succeed because of authentication of sharepoint system was windows authentication. PHP application support basic authentication so sharepoint does also. But the problem is when change authentication to basic or enable basic authenticaition for production site cause a security risk . So  SSL should be use but in our case it is one of out of issue.

so what we did , extending current site to new web application from Central Administration and enable basic authentication for extended site. Secure this extended site for specific application server that running php via Firewall rules and voila . Also suggested for external connection for this site using vpn or also able to use ssl if they able to change their code for it.

For Enabling Basic Authentication fallowing defined above senario :

1)  Extend your sharepoint site from Central Administration .

2) Enable basic authentication from IIS management console for extend web application. 

3) Select Authentication Provider for your newly extended site.

4) Enable Basic Authentication from configuration.

 

its done 🙂