HowTo: Create a quizzing application with SharePoint 2007

With SharePoint 2007 "Survey" list template, I recently created a quizzing application.  The thing with survey list is that it stack ranks the questions taking into account how many of the respondents favored each options within that question.  But for a quizzing application, we need to be able to stack rank the respondents on how many of their options where correct.  "Survey" list template, traditionally (by-design) cannot be used for a quiz requirement, but will some careful planning and custom-coding, I was able to make use of the SharePoint survey list template to organize a quiz within our organization.

Some preliminary work:

First, I had to setup a list that will host my questions, choices and the correct answer.  I also setup a custom field to figure-out if a question is already used in a quiz and to compute results for a particular quiz.  Below is a screen-shot of how this list looks like:

image

The tool to create quiz and compute results:

I created this tool based on the "business requirement" we had.  There are several hard-coding etc.,  However, it could be extended to suit your needs.  All that's really needed is to understand how the choices selected by respondents are to be read and computed to formulate their individual scores.

Tool UI to create the quiz:

image

The section highlighted above, is going to create a list of type survey.  It will use the "Quiz Questions and Answers" list as the source for filling itself up with questions and choices.  In my case, the quiz needs to be within a sub site.  I type in the full URL of the sub site and click "Get Lists" to populate the drop-down control.  Then provide the quiz title and description (actually the survey title and description) and specify the number of questions I need to consume in this quiz from the source list.  The "Day (1, 2, 3 etc.,)" is a parameter that I use to mark the questions in the source list "Quiz Questions and Answers" to denote they are already used.  This is mapped to the column "Used" shown in the screen-shot of "Quiz Questions and Answers" list above.  Once the quiz list is created after clicking the "Create Quiz" button shown above, the source list will look like the below screen-shot:

image

As we can see, the first 5 questions' "Used" column is now filled with 1, which is my custom parameter to denote those questions are used in day 1 quiz.  I also use this to compute results, specifically to see which questions I need to pick up from the entire list - this way it's going to be optimized and the computation would be much faster with minimum overhead on the server.

Code:

The GetLists() method returns all the lists that are not marked "hidden".  This is the method that will return our q & a list and populate the drop-down control.

 void GetLists()
         {
             try
             {
                 comboBox1.Items.Clear();
                 richTextBox1.Clear();
                 using (SPSite site = new SPSite(textBox1.Text.Trim()))
                 {
                     using (SPWeb web = site.OpenWeb())
                     {
                         SPListCollection lists = web.Lists;
                         foreach (SPList list in lists)
                         {
                             if (list.Hidden != true)
                                 comboBox1.Items.Add(list.Title);
                         }
                         comboBox1.SelectedIndex = 0;
                     }
                 }
             }
             catch (Exception _e)
             {
                 richTextBox1.Text += "Message: " + _e.Message + Environment.NewLine + Environment.NewLine +
                     "Stack Trace: " + _e.StackTrace;
             }
         }

The CreateQuiz() method creates the quiz list (of type Survey list).  The most important part here is the "foreach" loop that populates the questions and answers in the form of a survey question and choices.

 void CreateQuiz()
         {
             richTextBox1.Clear();
             try
             {
                 using (SPSite site = new SPSite(textBox1.Text.Trim()))
                 {
                     using (SPWeb web = site.OpenWeb())
                     {
                         int counter = 0;
                         int fldCnt = 3;
                         string question = string.Empty;
                         StringCollection choices = new StringCollection();
                         Guid quizId = web.Lists.Add(textBox2.Text.Trim(), textBox3.Text.Trim(), SPListTemplateType.Survey);
                         richTextBox1.Text += "Quiz list created.  Id: " + quizId.ToString() + Environment.NewLine;
                         SPList quiz = web.Lists[quizId];
                         quiz.ReadSecurity = 2;
                         quiz.WriteSecurity = 2;
                         quiz.AllowMultiResponses=false;
                         richTextBox1.Text += "ReadSecurity set to: " + quiz.ReadSecurity.ToString() + Environment.NewLine;
                         richTextBox1.Text += "WriteSecurity set to: " + quiz.WriteSecurity.ToString() + Environment.NewLine;
                         quiz.BreakRoleInheritance(false);
                         quiz.Update();
                         richTextBox1.Text += "Reading \"Unused\" items from source list" + Environment.NewLine;                        
                         foreach (SPListItem sListItem in web.Lists[comboBox1.SelectedItem.ToString()].Items)
                         {
                             if (counter < Convert.ToInt32(textBox4.Text.Trim()))
                             {
                                 if (sListItem["Used"].ToString().Equals("0"))
                                 {
                                     question = sListItem["Question"].ToString();
                                     choices.Add(sListItem["Option1"].ToString());
                                     choices.Add(sListItem["Option2"].ToString());
                                     choices.Add(sListItem["Option3"].ToString());
                                     choices.Add(sListItem["Option4"].ToString());
                                     choices.Add(sListItem["Option5"].ToString());
                                     counter++;
                                     string fldName = quiz.Fields.Add(question, SPFieldType.Choice, true, false, choices);
                                     SPFieldChoice choiceFld = (SPFieldChoice)quiz.Fields[fldCnt];
                                     choiceFld.EditFormat = SPChoiceFormatType.RadioButtons;
                                     choiceFld.Update();
                                     fldCnt++;
                                     richTextBox1.Text += "Added quiz question and options..." + Environment.NewLine;
                                     quiz.Update();
                                     choices.Clear();
                                     sListItem["Used"] = textBox6.Text.ToString();
                                     sListItem.Update();
                                     web.Update();
                                 }
                             }
                             else
                             {
                                 break;
                             }                            
                         }
                         if (textBox1.Text.EndsWith("/"))
                         {
                             richTextBox1.Text += "Quiz URL: " + HttpUtility.UrlPathEncode(textBox1.Text.Trim() + "Lists/" + textBox2.Text.Trim() + "/NewForm.aspx") + Environment.NewLine;
                         }
                         else
                         {
                             richTextBox1.Text += "Quiz URL: " + HttpUtility.UrlPathEncode(textBox1.Text.Trim() + "/Lists/" + textBox2.Text.Trim() + "/NewForm.aspx") + Environment.NewLine;
                         }
                     }
                 }
                 richTextBox1.Text += "All suskess...!";
             }
             catch(Exception _e)
             {
                 richTextBox1.Text += "Message: " + _e.Message + Environment.NewLine + Environment.NewLine +
                     "Stack Trace: " + _e.StackTrace;
             }
         }

The permissions:

After the quiz list is created there's one other thing I had to do, which is to setup permissions.  In my case, it was a quiz organized within my org so we had a security distribution list covering all the prospective quiz takers.  So, I created a new "Permission Level" in SharePoint with the following options turned on:

  • Add Items - Add items to lists, add documents to document libraries, and add Web discussion comments.
  • View Items - View items in lists, documents in document libraries, and view Web discussion comments.
  • View Application Pages - View forms, views, and application pages. Enumerate lists.
  • View Pages - View pages in a Web site.
  • Open - Allows users to open a Web site, list, or folder in order to access items inside that container.

Now I have my custom permission level with the kind of permission I need.  I also have a new quiz list created.  I simply assign the security distribution list to the quiz list with the custom permission level I created.  I can do this through code too, however, do to time constraint (I built this quizzing application in just under 4 hrs time), I opted to do this manually.

Well, in the code, the Read/Write Securities for the survey list are set to 2, which means "Users have Read access only to items that they create" and "Write only my items" respectively.  However, once a user answers all questions and submits the quiz, he/she can always edit it at anytime or even delete his/her response and attend a quiz again.  One of my "business requirement" was to prevent this scenario and custom permission levels just did that trick.  If the above is done then when a user responds to the quiz and tries to view their response - they can, however they will not be able to edit/delete their response.

"And the winner is..." - the computation part:

Now, coming to the quiz winner computation part as shown below:

image

On clicking "Get Quiz Lists" the drop-down will be populated with lists of type survey.  And clicking "Compute Results" will create another list sorted according to the total score and the earliest response.  This results list is also available as an STP file enclosed in this post.

Code:

The GetQuizLists() method populates the quiz lists drop-down with survey lists.

 void GetQuizLists()
         {
             try
             {
                 comboBox2.Items.Clear();
                 using (SPSite site = new SPSite(textBox5.Text.Trim()))
                 {
                     using (SPWeb web = site.OpenWeb())
                     {
                         foreach (SPList list in web.Lists)
                         {
                             if (list.BaseType == SPBaseType.Survey)
                             {
                                 comboBox2.Items.Add(list.Title);
                             }
                         }
                         comboBox2.SelectedIndex = 0;
                     }
                 }
             }
             catch (Exception _e)
             {
                 richTextBox1.Text += "Message: " + _e.Message + Environment.NewLine + Environment.NewLine +
                     "Stack Trace: " + _e.StackTrace;
             }
         }

The ComputeResults() method is the most important method that computes who the winner is depending on the Nth day of the quiz.  It compares individual quiz takers' response with the correct answer and increments a counter to compute the total score for an individual.  It does this for all the quiz takers and finally creates another results list using a template (enclosed).  This section in the code is where you'll find multiple hard-coding stuffs, so just go through the code and customize it per your need.

 void ComputeResults()
         {
             richTextBox1.Clear();
  
             using (SPSite site = new SPSite(textBox5.Text.Trim()))
             {
                 using (SPWeb web = site.OpenWeb())
                 {
                     int score = 0;
                     SPList sList = web.Lists["Quiz Questions and Answers"];
                     SPQuery query = new SPQuery();
                     query.Query = "<Where><Eq><FieldRef Name='Used'/><Value Type='Number'>" +
                         Convert.ToInt32(textBox7.Text.Trim()) + "</Value></Eq></Where>";
                     SPListItemCollection sItems = sList.GetItems(query);
                     string name = string.Empty;
                     DateTime datetime = DateTime.Now;
                     string quizTitle = comboBox2.SelectedItem.ToString();
                     SPList resultList = null;
                     foreach (SPListItem response in web.Lists[comboBox2.SelectedItem.ToString()].Items)
                     {
                         foreach (SPListItem sItem in sItems)
                         {
                             name = (string)response["Created By"];
                             name = name.Substring(name.IndexOf("#") + 1);
                             datetime = (DateTime)response["Modified"];
                             string ans = (string)response[sItem["Question"].ToString()];
                             if (ans.Equals(sItem["Correct Answer"].ToString().Trim()))
                             {
                                 score++;
                             }
                         }
  
                         SPListTemplate listTemplate = site.GetCustomListTemplates(web)["quiz_results"];
                         Guid newResultList = new Guid();
                         try
                         {
                             newResultList = web.Lists["Results for " + quizTitle].ID;
                         }
                         catch (ArgumentException _ae)
                         {
                             newResultList = web.Lists.Add("Results for " + quizTitle, "quiz results", listTemplate);
                             web.Update();
                         }
                         resultList = web.Lists[newResultList];
                         SPListItem resultItem = resultList.Items.Add();
                         resultItem["Login"] = name;
                         resultItem["Points"] = score;
                         resultItem["DateTime"] = datetime;
                         resultItem.Update();
                         score = 0;
                     }
                     richTextBox1.Text += "All done... check \"https://mossquiz" + resultList.DefaultViewUrl + "\" for results" + Environment.NewLine;                    
                 }
             }
            
  
             try
             { }
             catch (Exception _e)
             {
                 richTextBox1.Text += "Message: " + _e.Message + Environment.NewLine + Environment.NewLine +
                     "Stack Trace: " + _e.StackTrace;
             }
         }

End Note:

SharePoint being a collaborative and sharing platform should have provisioned such a quizzing template out of the box, but sadly there isn't one.  However, there's lot of demand for such utilities because most organizations conduct quiz/test of these sort a lot targeted towards readiness and learning.  The above solution can also be built into a feature and deployed as a solution package, however, that will be a larger implementation as we might have to automate few things and provide a web interface to manage it.

I hope this post and the tool was useful to you as it was highly useful to me (have used it in more than one quizzing events and so far am successful :) ).

Keep exploring!

CreateQuiz.zip