5.4. Tutorial browser (tutorial-browser.rsl)

module Student;

from Admin import Accounts;
from Login import LoginCookie;
from Data import all;
from Page import all;
from tutorial import all;
export all;

(*****************************************************************************)

object TutorialBrowser is
   components:
      browseTab:BrowseTab and
      searchTab:SearchTab and
      historyTab:HistoryTab;
   description: (*
      Highest-level model of the Tutorials window in the Student interface.
      Consists of three tabs used in tutorial location.
   *);
end TutorialBrowser;

(*****************************************************************************)

object BrowseTab is
   components:
      departmentGroups:DepartmentGroup*;
   description: (*
      The main Tutorials tab, this contains all tutorials in the database,
      arranged by department.
   *);
end BrowseTab;

object DepartmentGroup is
   components:
      departmentName:DepartmentName and
      courseGroups:CourseGroup*;
   description: (*
      Further subdivides the tutorials in a department by course.
   *);
end DepartmentGroup;

object CourseGroup is
   components:
      courseNumber:CourseNumber and
      authorGroups:AuthorGroup*;
   description: (*
      The CourseGroup is used to group tutorials by author. It consists of a
      CourseNumber and a collection of AuthorGroups.
   *);
end Course;

object AuthorGroup is
   components:
      authorID:UserID and
      tutorialGroups:TutorialGroup* and
      tutorials:TutorialRecord*;
   description: (*
      The AuthorGroup contains all tutorials for a particular class written by
      the same author. It consists of an authorID and a collection of
      TutorialGroups and TutorialRecords.
   *);
end AuthorGroup;

object TutorialGroup is
   components:
      tutorialGroups:TutorialGroup* and
      tutorials:TutorialRecord*;
   description: (*
      A TutorialGroup is used to subdivide tutorials written by a particular
      author into additional categories. It is analogous to a file folder,
      consiting of a collection of TutorialGroups and TutorialRecords.
   *);
end TutorialGroup;

(*****************************************************************************)

object SearchTab is
   components:
      searchName:SearchString and
      searchKeywords:SearchString and
      searchDepartmentName:SearchString and
      searchCourseNumber:SearchInteger and
      searchAuthorFirstName:SearchString and
      searchAuthorLastName:SearchString;
   description: (*
      This Tutorials tab allows the user to search for tutorials by specifying
      certain search parameters.
   *);
end SearchTab;

object SearchString is string
   description: (*
      A generic string used for a parameter in the tutorial search operation.
   *);
end SearchString;

object SearchInteger is integer
   description: (*
      A generic integer used for a parameter in the tutorial search operation.
   *);
end SearchInteger;

operation FindTutorial is
   inputs:
      cookie:LoginCookie and
      accounts:Accounts and
      tutorialDB:TutorialDB and
      pageDB:PageDB and
      searchName:SearchString and
      searchKeywords:SearchString and
      searchDepartmentName:SearchString and
      searchCourseNumber:SearchInteger and
      searchAuthorFirstName:SearchString and
      searchAuthorLastName:SearchString;
   outputs:
      matchingTutorials:TutorialRecord*;
   precondition: cookie.isConnected;
   postcondition:
      (* Skip a parameter if it is not supplied, otherwise assert that the
         parameter matches the corresponding aspect of the file *)
      forall (tutorialRecord in matchingTutorials) (
         (searchName = nil or StringContains(tutorialRecord.tutorial.title, searchName)) and
         (searchKeywords = nil or TutorialContains(tutorialRecord, searchKeywords)) and
         (searchDepartmentName = nil or StringContains(tutorialRecord.class.departmentName, searchDepartmentName)) and
         (searchCourseNumber = nil or tutorialRecord.class.courseNumber = searchCourseNumber) and
         (searchAuthorFirstName = nil or GetFirstName(accounts, tutorialRecord.authorID) = searchAuthorFirstName) and
         (searchAuthorLastName = nil or GetLastName(accounts, tutorialRecord.authorID) = searchAuthorLastName)
      );
   description: (*
      Given some identifying properties for tutorials, FindTutorial retrieves
      zero or more tutorials that match the specified parameters. Any parameter
      that is left blank will be ignored.
   *);
end FindTutorial;

(* Returns true if s2 is a substring of s1, false otherwise *)
function StringContains(s1:string, s2:string)->boolean =
   (exists (x:integer | (x >= 1) and (x + #s2 <= #s1) ) s1[x : (x + #s2)] = s2);

(* Returns true if any of the pages in the tutorial contains all of the space-
   separated keywords, false otherwise *)
function TutorialContains(t:TutorialRecord, k:string)->boolean =
   ...;

(* Returns the first name of the user in Accounts with the specified UserID, or
   nil if no such user exists *)
function GetFirstName(a:Accounts, uid:UserID)->string =
   ...;

(* Returns the last name of the user in Accounts with the specified UserID, or
   nil if no such user exists *)
function GetLastName(a:Accounts, uid:UserID)->string =
   ...;

(*****************************************************************************)

object HistoryTab is
   components:
      favoriteTutorials:FavoriteTutorials and
      tutorialsInProgress:TutorialsInProgress and
      completedTutorials:CompletedTutorials;
   description: (*
      This Tutorials tab allows the user to browse their tutorial history,
      including completed, incomplete, and bookmarked tutorials.
   *);
end HistoryTab;

object FavoriteTutorials is
   components:
      tutorialIDs:TutorialID*;
   description: (*
      This subfolder of the History tab holds all tutorials that the user has
      bookmarked as 'Favorites'.
   *);
end FavoriteTutorials;

operation AddFavorite is
   inputs:
      cookie:LoginCookie and
      ft:FavoriteTutorials and
      newID:TutorialID;
   outputs:
      ft':FavoriteTutorials;
   precondition:
      cookie.isConnected and
      cookie.isAuthenticated and
      (not exists (tID in ft.tutorialIDs) tID = newID);
   postcondition:
      forall (tID':TutorialID) (tID' in ft') iff ((tID' = newID) or (tID' in ft));
   description: (*
      Adds a tutorial to the Favorites folder if it is not already there.
   *);
end AddFavorite;

operation RemoveFavorite is
   inputs:
      cookie:LoginCookie and
      ft:FavoriteTutorials and
      pageID:PageID;
   outputs:
      ft':FavoriteTutorials;
   precondition:
      cookie.isConnected and
      cookie.isAuthenticated and
      pageID in ft;
   postcondition:
      forall (pID':PageID) (pID' in ft') iff ((pID' != pageID) or (pID' in ft));
   description: (*
      Removes a tutorial from the Favorites folder.
   *);
end RemoveFavorite;

object TutorialsInProgress is
   components:
      pageIDs:PageID*;
   description: (*
      This subfolder of the History tab holds all tutorials that the user has
      begun but has not navigated to completion.
   *);
end TutorialsInProgress;

object CompletedTutorials is
   components:
      pageIDs:PageID*;
   description: (*
      This subfolder of the History tab holds all tutorials that the user has
      fully completed.
   *);
end CompletedTutorials;

operation CompleteTutorial is
   inputs:
      cookie:LoginCookie and
      tip:TutorialsInProgress and
      ct:CompletedTutorials and
      pID:PageID;
   outputs:
      tip':TutorialsInProgress and
      ct':CompletedTutorials;
   precondition:
      cookie.isConnected and
      cookie.isAuthenticated;
   postcondition:
      (forall (pID':PageID) (pID' in tip') iff ((pID' != pID) or (pID' in tip))) and
      (forall (pID':PageID) (pID' in ct' ) iff ((pID'  = pID) or (pID' in ct )));
   description: (*
      Moves a tutorial from the Tutorials In Progress list to the Completed Tutorials list.
      Precondition has been left open because it is not necessary for a tutorial to be on
      the Tutorials In Progress list when completed, even though this should always be the
      case.
   *);
end CompleteTutorial;

(*****************************************************************************)

end Student;





Prev: Tutorials | Next: Tutorial viewer | Up: spec | Top: index