Beispiel #1
0
        StoredLearningSession CreateAttemptIfRequired(bool transitionToComplete)
        {
            // NotStarted --> Active or Completed or Final
            if (Assignment.IsELearning)
            {
                // create an attempt for this learner assignment
                StoredLearningSession learningSession = StoredLearningSession.CreateAttempt(Assignment.Store.PackageStore, LearnerId, LearnerAssignmentId, Assignment.RootActivityId,
                                                                                            Assignment.Store.Settings.LoggingOptions);

                // start the assignment, forcing selection of a first activity
                learningSession.Start(true);

                // if NotStarted --> Completed or Final, transition to the Completed state
                if (transitionToComplete)
                {
                    // transition to Completed
                    learningSession.Exit();
                }

                // save changes to <learningSession>
                learningSession.CommitChanges();

                return(learningSession);
            }
            else
            {
                return(null);
            }
        }
Beispiel #2
0
        [SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]    // parameters are validated
        protected void AppendContentFrameDetails(LearningSession session, StringBuilder sb)
        {
            FramesetUtil.ValidateNonNullParameter("sb", sb);
            FramesetUtil.ValidateNonNullParameter("session", session);

            // The URL for attempt-based content frames is:
            // http://<...basicWebApp>/Content.aspx/<AssignmentView>/<LearnerAssignmentId>/otherdata/
            // the otherdata depends on the view
            sb.Append(String.Format(CultureInfo.InvariantCulture, "/{0}", Convert.ToInt32(AssignmentView, NumberFormatInfo.InvariantInfo)));

            StoredLearningSession slsSession = session as StoredLearningSession;

            if (slsSession == null)
            {
                // Not attempt-based view
            }
            else
            {
                sb.AppendFormat("/{0}", LearnerAssignmentGuidId.ToString());

                // In review & ra views, append the current activity id
                if ((slsSession.View == SessionView.Review) || (slsSession.View == SessionView.RandomAccess))
                {
                    sb.AppendFormat("/{0}", FramesetUtil.GetStringInvariant(slsSession.CurrentActivityId));
                }
            }
        }
Beispiel #3
0
        void CompleteAssignment(StoredLearningSession newSession, AssignmentSaver saver)
        {
            LearnerAssignmentState newStatus = LearnerAssignmentState.Completed;
            bool?isFinal = false;

            if (Assignment.AutoReturn)
            {
                newStatus = LearnerAssignmentState.Final;
                isFinal   = true;
            }


            if (newSession == null)
            {
                float?finalPoints = null;
                if (Status == LearnerAssignmentState.Active && Assignment.IsELearning)
                {
                    finalPoints = FinishSession();
                }

                Save(newStatus, isFinal, NonELearningStatus(AttemptStatus.Completed), finalPoints, saver);
            }
            else
            {
                Save(newStatus, isFinal, NonELearningStatus(AttemptStatus.Completed), newSession.TotalPoints, saver);
            }

            Status = newStatus;
        }
Beispiel #4
0
        /// <summary>
        /// Allows the app to take action when the session is ending.
        /// </summary>
        public void ProcessSessionEnd(LearningSession session, ref string messageTitle, ref string message)
        {
            // Session ending results in message shown to the user.
            if (session.View == SessionView.Execute)
            {
                StoredLearningSession slsSession = session as StoredLearningSession;
                if (slsSession != null)
                {
                    // The rollup and/or sequencing process may have changed the state of the attempt. If so, there are some cases
                    // that cannot continue so show an error message.
                    switch (slsSession.AttemptStatus)
                    {
                    case AttemptStatus.Abandoned:
                        messageTitle = IUDICO.TestingSystem.Localization.getMessage("HID_SessionAbandonedTitle");
                        message      = IUDICO.TestingSystem.Localization.getMessage("FRM_ExecuteViewAbandonedSessionMsg");
                        break;

                    case AttemptStatus.Completed:
                        messageTitle = IUDICO.TestingSystem.Localization.getMessage("HID_SessionCompletedTitle");
                        message      = IUDICO.TestingSystem.Localization.getMessage("FRM_ExecuteViewCompletedSessionMsg");
                        break;

                    case AttemptStatus.Suspended:
                        messageTitle = IUDICO.TestingSystem.Localization.getMessage("HID_SessionSuspendedTitle");
                        message      = IUDICO.TestingSystem.Localization.getMessage("FRM_ExecuteViewSuspendedSessionMsg");
                        break;
                    }
                }
            }
        }
Beispiel #5
0
        /// <summary>
        /// Creates attempt on given organization and returns attempt identifier.
        /// </summary>
        /// <param name="orgID">Long integer value represents organization identifier to create attempt on.</param>
        /// <returns>Long integer value, representing attempt identifier of created attempt.</returns>
        public long CreateAttempt(long orgID)
        {
            ActivityPackageItemIdentifier organizationID = new ActivityPackageItemIdentifier(orgID);

            StoredLearningSession session = StoredLearningSession.CreateAttempt(this.PStore, this.CurrentUserIdentifier, organizationID, LoggingOptions.LogAll);

            long attemptID = session.AttemptId.GetKey();

            return(attemptID);
        }
Beispiel #6
0
        public static void AppendContentFrameDetails(LearningSession session, StringBuilder sb)
        {
            // The URL for attempt-based content frames is:
            // http://<...basicWebApp>/Content.aspx/<view>/<attemptId>/otherdata/
            // the otherdata depends on the view
            sb.Append(string.Format(CultureInfo.CurrentCulture, "/{0}", Convert.ToInt32(session.View)));

            StoredLearningSession slsSession = session as StoredLearningSession;

            sb.AppendFormat("/{0}", slsSession.AttemptId.GetKey().ToString());
        }
Beispiel #7
0
        /// <summary>Returns the assignment.</summary>
        public void Return(AssignmentSaver saver)
        {
            CheckUserIsInstructor();

            StoredLearningSession session = null;

            // Check the status
            switch (Status)
            {
            case LearnerAssignmentState.NotStarted:
                // Force collection & return
                session = CreateAttemptIfRequired(false);
                break;

            case LearnerAssignmentState.Active:
                // Force collection & return
                break;

            case LearnerAssignmentState.Completed:
                break;

            case LearnerAssignmentState.Final:
                // No need to return
                return;

            default:
                // New status added
                break;
            }

            LearnerAssignmentState newStatus = LearnerAssignmentState.Final;

            if (session == null)
            {
                Save(newStatus, true, NonELearningStatus(AttemptStatus.Completed), null, saver);
            }
            else
            {
                Save(newStatus, true, NonELearningStatus(AttemptStatus.Completed), session.TotalPoints, saver);
            }

            Status = newStatus;

            if (Assignment.EmailChanges)
            {
                saver.SendReturnEmail(User, this);
            }

            if (Assignment.IsNonELearning)
            {
                saver.UpdateDropBoxPermissions(newStatus, User);
            }
        }
    protected void CreateAttemptButton_Click(object sender, EventArgs e)
    {
        // the hidden "Create Attempt" button was auto-clicked by script on page load...

        // prevent script from clicking "Create Attempt" again
        AutoPostScript.Visible = false;

        // hide the "please wait" panel
        PleaseWait.Visible = false;

        // the OrganizationId hidden form element contains the ID of the organization to attempt --
        // try to create a new attempt based on that ID; an organization is a root-level activity,
        // so OrganizationId is actually an ActivityPackageItemIdentifier
        try
        {
            // set <currentUser> to information about the current user; we
            // need the current user's UserItemIdentifier
            LStoreUserInfo currentUser = GetCurrentUserInfo();

            // set <organizationId> from the OrganizationId hidden form element as described above
            ActivityPackageItemIdentifier organizationId = new ActivityPackageItemIdentifier(
                Convert.ToInt64(OrganizationId.Value, CultureInfo.InvariantCulture));

            // create an attempt on <organizationId>
            StoredLearningSession session = StoredLearningSession.CreateAttempt(PStore,
                                                                                currentUser.Id, organizationId, LoggingOptions.LogAll);

            // the operation was successful, and there are no messages to display to the user, so
            // update the AttemptId hidden form element with the ID of the newly-created attempt,
            // update the parent page, and close the dialog
            AttemptId.Value = Convert.ToString(session.AttemptId.GetKey(), CultureInfo.InvariantCulture);
            UpdateParentPageScript.Visible = true;
            CloseDialogScript.Visible      = true;
        }
        catch (Exception ex)
        {
            // an unexpected error occurred -- display a generic message that
            // doesn't include the exception message (since that message may
            // include sensitive information), and write the exception message
            // to the event log
            ErrorIntro.Visible   = true;
            ErrorMessage.Visible = true;
            ErrorMessage.Controls.Add(new System.Web.UI.LiteralControl(
                                          Server.HtmlEncode("A serious error occurred.  Please contact your system administrator.  More information has been written to the server event log.")));
            LogEvent(System.Diagnostics.EventLogEntryType.Error,
                     "An exception occurred while creating an attempt:\n\n{0}\n\n", ex.ToString());
            Buttons.Visible = true;
        }
    }
Beispiel #9
0
        /// <summary>
        /// Creates attempt on given organization and returns attempt identifier.
        /// </summary>
        /// <param name="orgID">Long integer value represents organization identifier to create attempt on.</param>
        /// <returns>Long integer value, representing attempt identifier of created attempt.</returns>
        protected AttemptItemIdentifier CreateAttempt(long orgID, int topicId)
        {
            ActivityPackageItemIdentifier organizationID = new ActivityPackageItemIdentifier(orgID);

            StoredLearningSession session = StoredLearningSession.CreateAttempt(this.PStore, this.GetCurrentUserIdentifier(), organizationID, LoggingOptions.LogAll);
            // TODO: add IudicoTopicRef
            LearningStoreJob            job = LStore.CreateJob();
            Dictionary <string, object> dic = new Dictionary <string, object>();

            dic.Add(Schema.AttemptItem.IudicoThemeRef, topicId);
            job.UpdateItem(session.AttemptId, dic);
            job.Execute();

            return(session.AttemptId);
        }
Beispiel #10
0
        /// <summary>
        /// Delegate implementation to allow the frameset to take action on a session view request. This allows SLK and
        /// BWP to have different behavior and messages about which requests are not valid.
        /// </summary>
        public bool ProcessViewRequest(SessionView view, LearningSession session)
        {
            this.Completed = false;
            switch (view)
            {
            case SessionView.Execute:
            {
                StoredLearningSession slsSession = session as StoredLearningSession;
                if (slsSession != null)
                {
                    if (slsSession.AttemptStatus == AttemptStatus.Completed)
                    {
                        this.RegisterError(
                            ResHelper.GetMessage(Localization.GetMessage("FRM_InvalidAttemptStatusForViewTitle")),
                            ResHelper.GetMessage(Localization.GetMessage("FRM_ExecuteViewCompletedSessionMsg")),
                            false);
                        this.Completed = true;
                        return(false);
                    }
                    else if (slsSession.AttemptStatus == AttemptStatus.Abandoned)
                    {
                        this.RegisterError(
                            ResHelper.GetMessage(Localization.GetMessage("FRM_InvalidAttemptStatusForViewTitle")),
                            ResHelper.GetMessage(Localization.GetMessage("FRM_ExecuteViewAbandonedSessionMsg")),
                            false);
                        return(false);
                    }
                }
            }
            break;

            case SessionView.Review:
                // BWP does not provide review view
                this.RegisterError(
                    ResHelper.GetMessage(Localization.GetMessage("FRM_ViewNotSupportedTitle")),
                    ResHelper.GetMessage(Localization.GetMessage("FRM_ReviewViewNotSupportedMsg")),
                    false);
                break;

            case SessionView.RandomAccess:
                this.RegisterError(
                    ResHelper.GetMessage(Localization.GetMessage("FRM_ViewNotSupportedTitle")),
                    ResHelper.GetMessage(Localization.GetMessage("FRM_RAViewNotSupportedMsg")),
                    false);
                break;
            }
            return(true);
        }
Beispiel #11
0
        /// <summary>
        /// Deletes pacakge and related attempts from database.
        /// </summary>
        /// <param name="packId">Long integer value represents package identifier.</param>
        protected void DeletePackage(long packId)
        {
            // set <packageId> to the ID of this package
            PackageItemIdentifier packageId = new PackageItemIdentifier(packId);

            // before we delete the package, we need to delete all attempts on the package --
            // the following query looks for those attempts
            LearningStoreJob   job   = LStore.CreateJob();
            LearningStoreQuery query = LStore.CreateQuery(
                Schema.MyAttempts.ViewName);

            query.AddCondition(Schema.MyAttempts.PackageId,
                               LearningStoreConditionOperator.Equal, packageId);
            query.AddCondition(Schema.MyAttempts.AttemptId,
                               LearningStoreConditionOperator.NotEqual, null);
            query.AddColumn(Schema.MyAttempts.AttemptId);
            query.AddSort(Schema.MyAttempts.AttemptId,
                          LearningStoreSortDirection.Ascending);
            job.PerformQuery(query);
            DataTable             dataTable         = job.Execute <DataTable>();
            AttemptItemIdentifier previousAttemptId = null;

            // loop once for each attempt on this package
            foreach (DataRow dataRow in dataTable.Rows)
            {
                // set <attemptId> to the ID of this attempt
                AttemptItemIdentifier attemptId;
                LStoreHelper.CastNonNull(dataRow["AttemptId"], out attemptId);

                // if <attemptId> is a duplicate attempt ID, skip it; note that the query
                // results are sorted by attempt ID (see above)
                if ((previousAttemptId != null) &&
                    (previousAttemptId.GetKey() == attemptId.GetKey()))
                {
                    continue;
                }

                // delete this attempt
                StoredLearningSession.DeleteAttempt(LStore, attemptId);

                // continue to the next attempt
                previousAttemptId = attemptId;
            }

            // delete the package
            PStore.DeletePackage(packageId);
        }
Beispiel #12
0
        /// <summary>
        /// Creates attempt on given organization and returns attempt identifier.
        /// </summary>
        /// <param name="orgId">Long integer value represents organization identifier to create attempt on.</param>
        /// <param name="curriculumChapterTopicId">Int32 value representing id of curriculum chapter topic.</param>
        /// <param name="topicType"><see cref="TopicTypeEnum"/> value defines part of topic.</param>
        /// <returns>Long integer value, representing attempt identifier of created attempt.</returns>
        protected AttemptItemIdentifier CreateAttempt(long orgId, int curriculumChapterTopicId, TopicTypeEnum topicType)
        {
            var organizationId = new ActivityPackageItemIdentifier(orgId);

            StoredLearningSession session = StoredLearningSession.CreateAttempt(
                this.PStore, this.GetCurrentUserIdentifier(), organizationId, LoggingOptions.LogAll);
            LearningStoreJob job = this.LStore.CreateJob();
            var dic = new Dictionary <string, object>
            {
                { Schema.AttemptItem.IudicoCurriculumChapterTopicRef, curriculumChapterTopicId },
                { Schema.AttemptItem.IudicoTopicType, topicType }
            };

            job.UpdateItem(session.AttemptId, dic);
            job.Execute();

            return(session.AttemptId);
        }
Beispiel #13
0
        void ReactivateSession()
        {
            if (AttemptId == null)
            {
                throw new InternalErrorException("SLK1010");
            }

            StoredLearningSession learningSession = new StoredLearningSession(SessionView.RandomAccess, AttemptId, Assignment.Store.PackageStore);

            // reactivate the attempt
            learningSession.Reactivate(ReactivateSettings.ResetEvaluationPoints);
            learningSession.CommitChanges();

            // restart the attempt
            learningSession = new StoredLearningSession(SessionView.Execute, AttemptId, Assignment.Store.PackageStore);
            learningSession.Start(true);
            learningSession.CommitChanges();
            // NOTE: if (learningSession.AttemptStatus != AttemptStatus.Active) then the
            // restart process failed -- but there's not much we can do about it, and throwing
            // an exception may make matters worse
        }
Beispiel #14
0
        float?FinishSession()
        {
            if (AttemptId == null)
            {
                throw new InternalErrorException("SLK1007");
            }

            // set <learningSession> to refer to the attempt associated with this learner assignment
            StoredLearningSession learningSession = new StoredLearningSession(SessionView.Execute, AttemptId, Assignment.Store.PackageStore);

            // transition the attempt to "Completed" state; note that this will initialize the "content score", i.e. the score computed from the content
            if (learningSession.HasCurrentActivity)
            {
                // make sure that if the content wants to suspend itself, it does
                learningSession.ProcessNavigationRequests();
            }

            learningSession.Exit();
            learningSession.CommitChanges();
            return(learningSession.TotalPoints);
        }
Beispiel #15
0
        /// <summary>Collects the assignment.</summary>
        public void Collect(AssignmentSaver saver)
        {
            CheckUserIsInstructor();
            StoredLearningSession session = null;

            // Check the status
            switch (Status)
            {
            case LearnerAssignmentState.NotStarted:
                session = CreateAttemptIfRequired(true);
                break;

            case LearnerAssignmentState.Active:
                break;

            case LearnerAssignmentState.Completed:
                // No need to collect
                return;

            case LearnerAssignmentState.Final:
                // No need to collect
                return;

            default:
                // New status added
                break;
            }

            CompleteAssignment(session, saver);

            if (Assignment.EmailChanges)
            {
                saver.SendCollectEmail(User);
            }

            if (Assignment.IsNonELearning)
            {
                saver.UpdateDropBoxPermissions(LearnerAssignmentState.Completed, User);
            }
        }
Beispiel #16
0
        /// <summary>Starts the assignment.</summary>
        public void Start()
        {
            CheckUserIsLearner();

            // Check the status
            switch (Status)
            {
            case LearnerAssignmentState.NotStarted:
                break;

            case LearnerAssignmentState.Active:
                return;

            case LearnerAssignmentState.Completed:
                throw InvalidTransitionException(LearnerAssignmentState.Completed, LearnerAssignmentState.Active);

            case LearnerAssignmentState.Final:
                throw InvalidTransitionException(LearnerAssignmentState.Final, LearnerAssignmentState.Active);

            default:
                // New status added
                break;
            }

            StoredLearningSession session = CreateAttemptIfRequired(false);

            LearnerAssignmentState newStatus = LearnerAssignmentState.Active;

            if (session == null)
            {
                Save(newStatus, null, NonELearningStatus(AttemptStatus.Active), null, null);
            }
            else
            {
                Save(newStatus, null, NonELearningStatus(AttemptStatus.Active), null, null);
            }

            Status = newStatus;
        }
        [SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]   // parameters are validated
        public void ProcessPageLoad(PackageStore packageStore,
                                    TryGetViewInfo TryGetViewInfo,
                                    TryGetAttemptInfo TryGetAttemptInfo,
                                    ProcessViewRequest ProcessViewRequest)
        {
            // These should never be a problem, however fxcop complains about them.
            FramesetUtil.ValidateNonNullParameter("TryGetViewInfo", TryGetViewInfo);
            FramesetUtil.ValidateNonNullParameter("TryGetAttemptInfo", TryGetAttemptInfo);
            FramesetUtil.ValidateNonNullParameter("ProcessViewRequest", ProcessViewRequest);
            FramesetUtil.ValidateNonNullParameter("packageStore", packageStore);

            // Session information that may be required
            SessionView           view;
            AttemptItemIdentifier attemptId; // not required for all views

            // Get View information. It determines what else to look for.
            if (!TryGetViewInfo(true, out view))
            {
                return;
            }

            // Based on View, request other information
            switch (view)
            {
            case SessionView.Execute:
            {
                // AttemptId is required
                if (!TryGetAttemptInfo(true, out attemptId))
                {
                    return;
                }

                // Create the session
                m_session = new StoredLearningSession(view, attemptId, packageStore);

                StoredLearningSession slsSession = m_session as StoredLearningSession;

                if (!ProcessViewRequest(SessionView.Execute, slsSession))
                {
                    return;
                }

                // If the attempt id appeared valid (that is, it was numeric), but does not represent a valid
                // attempt, the call to access AttemptStatus on the session will trigger an InvalidOperationException
                // containing a message for the user that the attempt id was not valid.
                switch (slsSession.AttemptStatus)
                {
                case AttemptStatus.Abandoned:
                {
                    // Can't do execute view on abandoned sessions. The application should have handled this
                    // in the ProcessViewRequest.
                    return;
                }

                case AttemptStatus.Active:
                {
                    // Check if it's started. If not, try starting it and forcing selection of a current activity.
                    if (!slsSession.HasCurrentActivity)
                    {
                        try
                        {
                            slsSession.Start(false);
                            slsSession.CommitChanges();
                        }
                        catch (SequencingException)
                        {
                            // Intentionally ignored. This means it was either already started or could not
                            // select an activity. In either case, just let the content frame ask the user to
                            // deal with selecting an activity.
                        }
                    }
                    else
                    {
                        // If the current activity is not active, then it's possible the frameset was removed from the
                        // user and the content suspended the current activity. In that case, we do this little trick
                        // and try suspending all the activities and then resuming them. The resume will simply resume
                        // all the activities between the current activity and the root. Other suspended activities
                        // will not be affected.
                        if (!slsSession.CurrentActivityIsActive)
                        {
                            slsSession.Suspend();
                            slsSession.Resume();
                            slsSession.CommitChanges();
                        }
                    }
                }
                break;

                case AttemptStatus.Completed:
                {
                    // Can't do execute view on completed sessions. The application should have handled this in the
                    // ProcessViewRequest.
                    return;
                }

                case AttemptStatus.Suspended:
                {
                    // Resume it
                    slsSession.Resume();
                    slsSession.CommitChanges();
                }
                break;

                default:
                    break;
                }
            }
            break;

            case SessionView.RandomAccess:
            {
                // AttemptId is required
                if (!TryGetAttemptInfo(true, out attemptId))
                {
                    return;
                }

                StoredLearningSession slsSession = new StoredLearningSession(SessionView.RandomAccess, attemptId, packageStore);

                m_session = slsSession;

                if (!ProcessViewRequest(SessionView.RandomAccess, slsSession))
                {
                    return;
                }

                // Move to the first activity with a resource.
                PostableFrameHelper.MoveToNextActivity(m_session);
            }
            break;

            case SessionView.Review:
            {
                // AttemptId is required
                if (!TryGetAttemptInfo(true, out attemptId))
                {
                    return;
                }

                // Create the session
                StoredLearningSession slsSession = new StoredLearningSession(view, attemptId, packageStore);
                m_session = slsSession;

                if (!ProcessViewRequest(SessionView.Review, m_session))
                {
                    return;
                }

                // Access a property. If the user doesn't have permission, this will throw exception
                if (m_session.HasCurrentActivity)
                {
                    // This is good. The 'if' statement is here to make compiler happy.
                }
            }
            break;
            }
        }
Beispiel #18
0
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] // it's not worth changing this now
        public void ProcessPageLoad(PackageStore packageStore,
                                    bool firstRendering,                                  // frameset is being initialized
                                    bool isPostBack,                                      // page was posted
                                    TryGetViewInfo TryGetViewInfo,
                                    TryGetAttemptInfo TryGetAttemptInfo,
                                    TryGetActivityInfo TryGetActivityInfo,
                                    GetResourcePath GetResourcePath,
                                    AppendContentFrameDetails appendContentFrameDetails,
                                    UpdateRenderContext updateRenderContext,
                                    ProcessPostedData ProcessPostedData,
                                    ProcessViewRequest ProcessViewRequest,
                                    ProcessPostedDataComplete ProcessPostedDataComplete,
                                    RegisterError registerError,
                                    GetErrorInfo getErrorInfo,
                                    GetFramesetMsg getFramesetMsg)
        {
            RegisterError             = registerError;
            UpdateRenderContext       = updateRenderContext;
            GetErrorInfo              = getErrorInfo;
            AppendContentFrameDetails = appendContentFrameDetails;
            GetFramesetMsg            = getFramesetMsg;

            m_isPostedPage = isPostBack;

            // If this is the first time the page is being rendered, just show 'please wait' and return.
            if (firstRendering)
            {
                // Initial page rendering, show "please wait"
                WritePleaseWaitToResponse(Response);
                Response.End();
                return;
            }

            SessionView view;

            // Get View information. It determines what else to look for.
            if (!TryGetViewInfo(true, out view))
            {
                return;
            }

            // There is something to display, so process the request...

            AttemptItemIdentifier attemptId;

            if (!TryGetAttemptInfo(true, out attemptId))
            {
                return;
            }

            StoredLearningSession slsSession = new StoredLearningSession(view, attemptId, packageStore);

            if (!ProcessViewRequest(view, slsSession))
            {
                return;
            }

            Session = slsSession;

            if (slsSession.View == SessionView.Execute)
            {
                // Check if the session can be executed...

                if (slsSession.AttemptStatus != AttemptStatus.Active)
                {
                    RegisterError(GetFramesetMsg(FramesetStringId.CannotDisplayContentTitle),
                                  GetFramesetMsg(FramesetStringId.SessionIsNotActiveMsg), false);
                    return;
                }

                if (!slsSession.CurrentActivityIsActive)
                {
                    RegisterError(GetFramesetMsg(FramesetStringId.SelectActivityTitleHtml),
                                  GetFramesetMsg(FramesetStringId.SelectActivityMessageHtml), true);
                    return;
                }
            }
            else if (slsSession.View == SessionView.Review)
            {
                // Get information about which activity to review, then make that the current activity.

                long activityId = -1;   // make compiler happy
                if (!TryGetActivityInfo(true, out activityId))
                {
                    return;
                }

                // Move to the requested activity. Under normal conditions, this should always succeed, since the frameset should be
                // giving this page a valid activity id.
                MoveToActivity(slsSession, activityId);
            }

            else if (slsSession.View == SessionView.RandomAccess)
            {
                // Get information about which activity to edit, then make that the current activity.

                long activityId = -1;   // make compiler happy
                if (!TryGetActivityInfo(true, out activityId))
                {
                    return;
                }

                // Move to the requested activity. Under normal conditions, this should always succeed, since the frameset should be
                // giving this page a valid activity id.
                MoveToActivity(slsSession, activityId);
            }

            if (isPostBack /* && !SessionEnded */)
            {
                //Process information from posted content
                if (!this.SessionIsReadOnly)
                {
                    HttpFileCollection files = Request.Files;
                    int numFiles             = files.Count;
                    Dictionary <string, HttpPostedFile> newFileCollection = new Dictionary <string, HttpPostedFile>(numFiles);

                    // Allow the application to process the form data
                    if (!ProcessPostedData(slsSession, Request, newFileCollection))
                    {
                        return;
                    }

                    // Allow MLC to process the form data
                    Session.ProcessFormData(Request.Form, newFileCollection);

                    // Allow application to do final processing after all posted data is processed.
                    ProcessPostedDataComplete(Session);

                    // If there was an error in processing form data, end the processing. This allows, for instance, to
                    // save the data, display an error and not have commands (such as 'move to next activity') executed.
                    if (HasError)
                    {
                        Session.CommitChanges();
                        return;
                    }
                }

                // Issue with Review view: where to get activity id? From URL or posted data?

                // Find out what the commands are and do them.
                ICollection <CommandInfo> commands = GetCommands();
                foreach (CommandInfo cmdInfo in commands)
                {
                    switch (cmdInfo.Command)
                    {
                    case Commands.DoNext:
                    {
                        // When leaving a current activity, we must allow navigation requests the SCO has made to be
                        // executed. If that results in changing the current activity, then do not also ask for another
                        // move.
                        if (!ProcessNavigationRequests(Session))
                        {
                            if (Session.IsMoveToNextValid())
                            {
                                MoveToNextActivity(Session);
                                ActivityHasChanged = true;
                            }
                        }
                        else
                        {
                            ActivityHasChanged = true;
                        }

                        if (!ActivityHasChanged)
                        {
                            // Moving to the next activity is not valid.

                            WriteError(ResHelper.Format(GetFramesetMsg(FramesetStringId.MoveToNextFailedHtml), ThemeFolderPath), true);
                        }
                    }
                    break;

                    case Commands.DoPrevious:
                    {
                        if (!ProcessNavigationRequests(Session))
                        {
                            if (Session.IsMoveToPreviousValid())
                            {
                                MoveToPreviousActivity(Session);
                                ActivityHasChanged = true;
                            }
                        }
                        else
                        {
                            ActivityHasChanged = true;
                        }


                        if (!ActivityHasChanged)
                        {
                            // Moving to the previous activity is not valid.
                            WriteError(ResHelper.Format(GetFramesetMsg(FramesetStringId.MoveToPreviousFailedHtml), ThemeFolderPath), true);
                        }
                    }
                    break;

                    case Commands.DoChoice:
                    case Commands.DoTocChoice:
                    {
                        // These commands are used to navigate to activities, and to navigate to the final 'submit' page.
                        // In SCORM content, these commands do different things. In LRM content (which is what we are
                        // in, since this is the posted page), they have identical effects.

                        // First check whether this is a request for the submit page or an activity.

                        string cmdData = cmdInfo.CommandData;
                        if (String.CompareOrdinal(cmdData, SubmitId) == 0)
                        {
                            // Requesting submit page. Do not change the current activity, but mark it as changed so that
                            // it appears to the user that it has changed.
                            ActivityHasChanged = true;
                            string title = GetFramesetMsg(FramesetStringId.SubmitPageTitleHtml);
                            string message;
                            string saveBtn = GetFramesetMsg(FramesetStringId.SubmitPageSaveButtonHtml);
                            if (Session.HasCurrentActivity)
                            {
                                message = GetFramesetMsg(FramesetStringId.SubmitPageMessageHtml);
                            }
                            else
                            {
                                message = GetFramesetMsg(FramesetStringId.SubmitPageMessageNoCurrentActivityHtml);
                            }
                            WriteSubmitPage(title, message, saveBtn);
                        }
                        else
                        {
                            long activityId;
                            if (long.TryParse(cmdData, out activityId))
                            {
                                // If the requested activity is the current activity, then do not do the navigation.
                                // We skip it because moving to the activity basically exits the current attempt and creates
                                // a new one. That new one also increments the attempt count. If we don't do the move, we
                                // pretend it was done. This will force the content frame to be reloaded with the current
                                // activity.
                                if (IsCurrentActiveActivity(activityId))
                                {
                                    ActivityHasChanged = true;
                                }
                                else
                                {
                                    if (!ProcessNavigationRequests(Session))
                                    {
                                        if (Session.IsMoveToActivityValid(activityId))
                                        {
                                            MoveToActivity(Session, activityId);
                                            ActivityHasChanged = true;
                                        }
                                    }
                                    else
                                    {
                                        ActivityHasChanged = true;
                                    }
                                }
                            }
                        }

                        if (!ActivityHasChanged)
                        {
                            // Moving to the selected activity is not valid.

                            WriteError(ResHelper.Format(GetFramesetMsg(FramesetStringId.MoveToActivityFailedHtml), ThemeFolderPath), true);
                        }
                    }
                    break;

                    case Commands.DoSave:
                    {
                        // Do nothing. The information will be saved since the page was posted.
                    }
                    break;

                    case Commands.DoSubmit:
                    {
                        if (Session.View == SessionView.Execute)
                        {
                            ProcessNavigationRequests(Session);
                            Session.Exit();
                        }

                        ActivityHasChanged = true;
                    }
                    break;
                    }
                }
            }

            // If an error has been registered (and it's not the submit
            // page rendering), don't attempt to render the content.
            if (HasError && !SubmitPageDisplayed)
            {
                if (!SessionIsReadOnly)
                {
                    Session.CommitChanges();
                }
                return;
            }

            // There was no error, so go ahead and render the content from the package.
            // If the current activity has changed in the processing of this page, then render the current activity's resource.
            // Otherwise, ask the application which resource to read.
            if (ActivityHasChanged)
            {
                // If the activity has changed, we render the content page without rendering the content. The page will then
                // reload the content frame with the new activity.
                if (!SessionIsReadOnly)
                {
                    Session.CommitChanges();
                }
            }
            else
            {
                // Render the requested file in the current activity.
                RenderPackageContent(GetResourcePath());

                // If there was no error, end the response. Otherwise, we wait and render the error on the page.
                if (!HasError)
                {
                    Response.End();
                }
            }
        }
         SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]   // parameter is validated
        public void ProcessSessionEnd(LearningSession session, ref string messageTitle, ref string message)
        {
            FramesetUtil.ValidateNonNullParameter("session", session);

            // If we have already been here, then there is nothing more to do.
            if (SessionEnded)
            {
                return;
            }

            LearnerAssignmentProperties la = GetLearnerAssignment();

            // Session ending results in message shown to the user.
            if (session.View == SessionView.Execute)
            {
                StoredLearningSession slsSession = session as StoredLearningSession;
                if (slsSession != null)
                {
                    // The rollup and/or sequencing process may have changed the state of the attempt. If so, there are some cases
                    // that cannot continue so show an error message.
                    switch (slsSession.AttemptStatus)
                    {
                    case AttemptStatus.Abandoned:
                        messageTitle = SlkFrameset.HID_SessionAbandonedTitle;
                        message      = SlkFrameset.HID_ExecuteViewAbandonedSessionMsg;
                        SessionEnded = true;
                        break;

                    case AttemptStatus.Completed:
                        messageTitle = SlkFrameset.HID_SessionCompletedTitle;
                        message      = SlkFrameset.HID_ExecuteViewCompletedSessionMsg;
                        SessionEnded = true;
                        break;

                    case AttemptStatus.Suspended:
                        messageTitle = SlkFrameset.HID_SessionSuspendedTitle;
                        message      = SlkFrameset.HID_ExecuteViewSuspendedSessionMsg;
                        // Do not set SessionEnded -- the session being suspended does not warrant ending the learner assignment
                        break;
                    }
                }

                if (SessionEnded)
                {
                    // Call FinishLearnerAssignment since the attempt has already been completed.
                    SlkStore.FinishLearnerAssignment(LearnerAssignmentGuidId);
                }
            }
            else if (session.View == SessionView.RandomAccess)
            {
                messageTitle = SlkFrameset.HID_GradingFinishedTitle;
                message      = SlkFrameset.HID_GradingFinishedMessage;
                StringBuilder sb = new StringBuilder(1000);
                sb.Append(message);
                sb.Append("<br><script>");

                // Write the assignment status to slkFrameMgr
                WriteSlkMgrInit(sb);

                sb.AppendLine("slkMgr = Slk_GetSlkManager();");
                sb.AppendFormat("slkMgr.LearnerAssignmentId = {0};\r\n",
                                JScriptString.QuoteString(FramesetUtil.GetStringInvariant(la.LearnerAssignmentId.GetKey()), false));

                sb.AppendFormat("slkMgr.Status = {0};\r\n",
                                JScriptString.QuoteString(SlkUtilities.GetLearnerAssignmentState(la.Status), false));

                if (AssignmentView == AssignmentView.Grading)
                {
                    string finalPointsValue = "null";
                    float? finalPoints      = la.FinalPoints;
                    if (finalPoints != null)
                    {
                        finalPointsValue = Convert.ToString(finalPoints.Value, CultureInfo.InvariantCulture.NumberFormat);
                    }
                    sb.AppendFormat("slkMgr.FinalPoints = {0};\r\n", finalPointsValue);
                }

                // Send information about total points (ie, computed points on the client).
                if (session != null)
                {
                    if (session.TotalPoints != null)
                    {
                        sb.AppendFormat("slkMgr.ComputedPoints = {0};\r\n",
                                        JScriptString.QuoteString(Convert.ToString(session.TotalPoints, CultureInfo.CurrentCulture.NumberFormat), false));
                    }
                    else
                    {
                        sb.AppendFormat("slkMgr.ComputedPoints = \"\";\r\n");
                    }

                    if (session.SuccessStatus != SuccessStatus.Unknown)
                    {
                        sb.AppendFormat("slkMgr.PassFail = {0};\r\n",
                                        JScriptString.QuoteString(((session.SuccessStatus == SuccessStatus.Passed) ? "passed" : "failed"), false));
                    }
                }
            }
        }
Beispiel #20
0
        // it's not worth changing this now
        public void ProcessPageLoad(
            PackageStore packageStore,
            bool firstRendering,
            // frameset is being initialized
            bool isPostBack,
            // page was posted
            TryGetViewInfo tryGetViewInfo,
            TryGetAttemptInfo tryGetAttemptInfo,
            TryGetActivityInfo tryGetActivityInfo,
            GetResourcePath getResourcePath,
            AppendContentFrameDetails appendContentFrameDetails,
            UpdateRenderContext updateRenderContext,
            ProcessPostedData processPostedData,
            ProcessViewRequest processViewRequest,
            ProcessPostedDataComplete processPostedDataComplete,
            RegisterError registerError,
            GetErrorInfo getErrorInfo,
            GetFramesetMsg getFramesetMsg)
        {
            this.RegisterError = registerError;
            this.UpdateRenderContext = updateRenderContext;
            this.GetErrorInfo = getErrorInfo;
            this.AppendContentFrameDetails = appendContentFrameDetails;
            this.GetFramesetMsg = getFramesetMsg;

            this.mIsPostedPage = isPostBack;

            // If this is the first time the page is being rendered, just show 'please wait' and return.
            if (firstRendering)
            {
                // Initial page rendering, show "please wait"
                WritePleaseWaitToResponse(this.Response);
                this.Response.End();
                return;
            }

            SessionView view;

            // Get View information. It determines what else to look for.
            if (!tryGetViewInfo(true, out view))
            {
                return;
            }

            // There is something to display, so process the request...

            AttemptItemIdentifier attemptId;
            if (!tryGetAttemptInfo(true, out attemptId))
            {
                return;
            }

            StoredLearningSession slsSession = new StoredLearningSession(view, attemptId, packageStore);

            if (!processViewRequest(view, slsSession))
            {
                return;
            }

            this.Session = slsSession;

            if (slsSession.View == SessionView.Execute)
            {
                // Check if the session can be executed...

                if (slsSession.AttemptStatus != AttemptStatus.Active)
                {
                    this.RegisterError(
                        this.GetFramesetMsg(FramesetStringId.CannotDisplayContentTitle),
                        this.GetFramesetMsg(FramesetStringId.SessionIsNotActiveMsg),
                        false);
                    return;
                }

                if (!slsSession.CurrentActivityIsActive)
                {
                    this.RegisterError(
                        this.GetFramesetMsg(FramesetStringId.SelectActivityTitleHtml),
                        this.GetFramesetMsg(FramesetStringId.SelectActivityMessageHtml),
                        true);
                    return;
                }
            }
            else if (slsSession.View == SessionView.Review)
            {
                // Get information about which activity to review, then make that the current activity.

                long activityId = -1; // make compiler happy
                if (!tryGetActivityInfo(true, out activityId))
                {
                    return;
                }

                // Move to the requested activity. Under normal conditions, this should always succeed, since the frameset should be 
                // giving this page a valid activity id.
                MoveToActivity(slsSession, activityId);
            }

            else if (slsSession.View == SessionView.RandomAccess)
            {
                // Get information about which activity to edit, then make that the current activity.

                long activityId = -1; // make compiler happy
                if (!tryGetActivityInfo(true, out activityId))
                {
                    return;
                }

                // Move to the requested activity. Under normal conditions, this should always succeed, since the frameset should be 
                // giving this page a valid activity id.
                MoveToActivity(slsSession, activityId);
            }

            if (isPostBack /* && !SessionEnded */)
            {
                // Process information from posted content
                if (!this.SessionIsReadOnly)
                {
                    HttpFileCollection files = this.Request.Files;
                    int numFiles = files.Count;
                    Dictionary<string, HttpPostedFile> newFileCollection =
                        new Dictionary<string, HttpPostedFile>(numFiles);

                    // Allow the application to process the form data
                    if (!processPostedData(slsSession, this.Request, newFileCollection))
                    {
                        return;
                    }

                    // Allow MLC to process the form data
                    this.Session.ProcessFormData(this.Request.Form, newFileCollection);

                    // Allow application to do final processing after all posted data is processed.
                    processPostedDataComplete(this.Session);

                    // If there was an error in processing form data, end the processing. This allows, for instance, to 
                    // save the data, display an error and not have commands (such as 'move to next activity') executed.
                    if (this.HasError)
                    {
                        this.Session.CommitChanges();
                        return;
                    }
                }

                // Issue with Review view: where to get activity id? From URL or posted data?

                // Find out what the commands are and do them.
                ICollection<CommandInfo> commands = this.GetCommands();
                foreach (CommandInfo cmdInfo in commands)
                {
                    switch (cmdInfo.Command)
                    {
                        case Commands.DoNext:
                            {
                                // When leaving a current activity, we must allow navigation requests the SCO has made to be 
                                // executed. If that results in changing the current activity, then do not also ask for another 
                                // move.
                                if (!ProcessNavigationRequests(this.Session))
                                {
                                    if (this.Session.IsMoveToNextValid())
                                    {
                                        MoveToNextActivity(this.Session);
                                        this.ActivityHasChanged = true;
                                    }
                                }
                                else
                                {
                                    this.ActivityHasChanged = true;
                                }

                                if (!this.ActivityHasChanged)
                                {
                                    // Moving to the next activity is not valid. 

                                    this.WriteError(
                                        ResHelper.Format(
                                            this.GetFramesetMsg(FramesetStringId.MoveToNextFailedHtml),
                                            this.ThemeFolderPath),
                                        true);
                                }
                            }
                            break;
                        case Commands.DoPrevious:
                            {
                                if (!ProcessNavigationRequests(this.Session))
                                {
                                    if (this.Session.IsMoveToPreviousValid())
                                    {
                                        MoveToPreviousActivity(this.Session);
                                        this.ActivityHasChanged = true;
                                    }
                                }
                                else
                                {
                                    this.ActivityHasChanged = true;
                                }

                                if (!this.ActivityHasChanged)
                                {
                                    // Moving to the previous activity is not valid.
                                    this.WriteError(
                                        ResHelper.Format(
                                            this.GetFramesetMsg(FramesetStringId.MoveToPreviousFailedHtml),
                                            this.ThemeFolderPath),
                                        true);
                                }
                            }
                            break;
                        case Commands.DoChoice:
                        case Commands.DoTocChoice:
                            {
                                // These commands are used to navigate to activities, and to navigate to the final 'submit' page.
                                // In SCORM content, these commands do different things. In LRM content (which is what we are 
                                // in, since this is the posted page), they have identical effects. 

                                // First check whether this is a request for the submit page or an activity.

                                string cmdData = cmdInfo.CommandData;
                                if (string.CompareOrdinal(cmdData, SubmitId) == 0)
                                {
                                    // Requesting submit page. Do not change the current activity, but mark it as changed so that 
                                    // it appears to the user that it has changed.
                                    this.ActivityHasChanged = true;
                                    string title = this.GetFramesetMsg(FramesetStringId.SubmitPageTitleHtml);
                                    string message;
                                    string saveBtn = this.GetFramesetMsg(FramesetStringId.SubmitPageSaveButtonHtml);
                                    if (this.Session.HasCurrentActivity)
                                    {
                                        message = this.GetFramesetMsg(FramesetStringId.SubmitPageMessageHtml);
                                    }
                                    else
                                    {
                                        message =
                                            this.GetFramesetMsg(FramesetStringId.SubmitPageMessageNoCurrentActivityHtml);
                                    }
                                    this.WriteSubmitPage(title, message, saveBtn);
                                }
                                else
                                {
                                    long activityId;
                                    if (long.TryParse(cmdData, out activityId))
                                    {
                                        // If the requested activity is the current activity, then do not do the navigation.
                                        // We skip it because moving to the activity basically exits the current attempt and creates
                                        // a new one. That new one also increments the attempt count. If we don't do the move, we 
                                        // pretend it was done. This will force the content frame to be reloaded with the current 
                                        // activity.
                                        if (this.IsCurrentActiveActivity(activityId))
                                        {
                                            this.ActivityHasChanged = true;
                                        }
                                        else
                                        {
                                            if (!ProcessNavigationRequests(this.Session))
                                            {
                                                if (this.Session.IsMoveToActivityValid(activityId))
                                                {
                                                    MoveToActivity(this.Session, activityId);
                                                    this.ActivityHasChanged = true;
                                                }
                                            }
                                            else
                                            {
                                                this.ActivityHasChanged = true;
                                            }
                                        }
                                    }
                                }

                                if (!this.ActivityHasChanged)
                                {
                                    // Moving to the selected activity is not valid. 

                                    this.WriteError(
                                        ResHelper.Format(
                                            this.GetFramesetMsg(FramesetStringId.MoveToActivityFailedHtml),
                                            this.ThemeFolderPath),
                                        true);
                                }
                            }
                            break;
                        case Commands.DoSave:
                            {
                                // Do nothing. The information will be saved since the page was posted.
                            }
                            break;
                        case Commands.DoSubmit:
                            {
                                if (this.Session.View == SessionView.Execute)
                                {
                                    ProcessNavigationRequests(this.Session);
                                    this.Session.Exit();
                                }

                                this.ActivityHasChanged = true;
                            }
                            break;
                    }
                }
            }

            // If an error has been registered (and it's not the submit 
            // page rendering), don't attempt to render the content.
            if (this.HasError && !this.SubmitPageDisplayed)
            {
                if (!this.SessionIsReadOnly)
                {
                    this.Session.CommitChanges();
                }
                return;
            }

            // There was no error, so go ahead and render the content from the package.
            // If the current activity has changed in the processing of this page, then render the current activity's resource.
            // Otherwise, ask the application which resource to read.
            if (this.ActivityHasChanged)
            {
                // If the activity has changed, we render the content page without rendering the content. The page will then 
                // reload the content frame with the new activity.
                if (!this.SessionIsReadOnly)
                {
                    this.Session.CommitChanges();
                }
            }
            else
            {
                // Render the requested file in the current activity.
                this.RenderPackageContent(getResourcePath());

                // If there was no error, end the response. Otherwise, we wait and render the error on the page.
                if (!this.HasError)
                {
                    this.Response.End();
                }
            }
        }
Beispiel #21
0
        [SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]   // parameters are validated
        public void ProcessPageLoad(PackageStore packageStore,
                                    TryGetViewInfo TryGetViewInfo,
                                    TryGetAttemptInfo TryGetAttemptInfo,
                                    ProcessViewRequest ProcessViewRequest)
        {
            // These should never be a problem, however fxcop complains about them.
            FramesetUtil.ValidateNonNullParameter("TryGetViewInfo", TryGetViewInfo);
            FramesetUtil.ValidateNonNullParameter("TryGetAttemptInfo", TryGetAttemptInfo);
            FramesetUtil.ValidateNonNullParameter("ProcessViewRequest", ProcessViewRequest);
            FramesetUtil.ValidateNonNullParameter("packageStore", packageStore);

            // Session information that may be required
            SessionView view;
            AttemptItemIdentifier attemptId; // not required for all views

            // Get View information. It determines what else to look for.
            if (!TryGetViewInfo(true, out view))
                return;

            // Based on View, request other information
            switch (view)
            {
                case SessionView.Execute:
                    {
                        // AttemptId is required
                        if (!TryGetAttemptInfo(true, out attemptId))
                            return;

                        // Create the session
                        m_session = new StoredLearningSession(view, attemptId, packageStore);
                        
                        StoredLearningSession slsSession = m_session as StoredLearningSession;

                        if (!ProcessViewRequest(SessionView.Execute, slsSession))
                        {
                            if (slsSession.AttemptStatus == AttemptStatus.Completed)
                            {

                            }
                            return;
                        }

                        // If the attempt id appeared valid (that is, it was numeric), but does not represent a valid 
                        // attempt, the call to access AttemptStatus on the session will trigger an InvalidOperationException
                        // containing a message for the user that the attempt id was not valid.
                        switch (slsSession.AttemptStatus)
                        {
                            case AttemptStatus.Abandoned:
                                {
                                    // Can't do execute view on abandoned sessions. The application should have handled this
                                    // in the ProcessViewRequest.
                                    return;
                                }
                            case AttemptStatus.Active:
                                {
                                    // Check if it's started. If not, try starting it and forcing selection of a current activity.
                                    if (!slsSession.HasCurrentActivity)
                                    {
                                        try
                                        {
                                            slsSession.Start(false);
                                            slsSession.CommitChanges();
                                        }
                                        catch (SequencingException)
                                        {
                                            // Intentionally ignored. This means it was either already started or could not 
                                            // select an activity. In either case, just let the content frame ask the user to 
                                            // deal with selecting an activity.
                                        }
                                    }
                                    else
                                    {
                                        // If the current activity is not active, then it's possible the frameset was removed from the 
                                        // user and the content suspended the current activity. In that case, we do this little trick
                                        // and try suspending all the activities and then resuming them. The resume will simply resume
                                        // all the activities between the current activity and the root. Other suspended activities
                                        // will not be affected.
                                        if (!slsSession.CurrentActivityIsActive)
                                        {
                                            slsSession.Suspend();
                                            slsSession.Resume();
                                            slsSession.CommitChanges();
                                        }
                                    }
                                }
                                break;
                            case AttemptStatus.Completed:
                                {
                                    // Can't do execute view on completed sessions. The application should have handled this in the 
                                    // ProcessViewRequest.
                                    return;
                                }
                            case AttemptStatus.Suspended:
                                {
                                    // Resume it
                                    slsSession.Resume();
                                    slsSession.CommitChanges();
                                }
                                break;
                            default:
                                break;
                        }

                    }
                    break;
                case SessionView.RandomAccess:
                    {
                        // AttemptId is required
                        if (!TryGetAttemptInfo(true, out attemptId))
                            return;

                        StoredLearningSession slsSession = new StoredLearningSession(SessionView.RandomAccess, attemptId, packageStore);
                        
                        m_session = slsSession;

                        if (!ProcessViewRequest(SessionView.RandomAccess, slsSession ))
                            return;

                        // Move to the first activity with a resource.
                        PostableFrameHelper.MoveToNextActivity(m_session);
                    }
                    break;
                case SessionView.Review:
                    {
                        // AttemptId is required
                        if (!TryGetAttemptInfo(true, out attemptId))
                            return;

                        // Create the session
                        StoredLearningSession slsSession = new StoredLearningSession(view, attemptId, packageStore);
                        m_session = slsSession;

                        if (!ProcessViewRequest(SessionView.Review, m_session))
                            return;

                        // Access a property. If the user doesn't have permission, this will throw exception
                        if (m_session.HasCurrentActivity)
                        {
                            // This is good. The 'if' statement is here to make compiler happy.
                        }
                    }
                    break;
            }
        }
Beispiel #22
0
    protected void DeletePackagesButton_Click(object sender, EventArgs e)
    {
        // the user clicked "Upload"...

        // hide the confirmation panel
        ConfirmMessage.Visible = false;

        // the PackagesToDelete hidden form element contains a comma-delimited list of IDs of
        // packages to delete (copied from <dialogArguments> on the client) -- attempt to delete
        // those packages, and set <deleted> to the IDs of packages successfully deleted
        List <string> deleted = new List <string>();

        try
        {
            // loop once for each package to delete
            foreach (string id in PackagesToDelete.Value.Split(','))
            {
                // set <packageId> to the ID of this package
                PackageItemIdentifier packageId = new PackageItemIdentifier(
                    Convert.ToInt64(id, CultureInfo.InvariantCulture));

                // before we delete the package, we need to delete all attempts on the package --
                // the following query looks for those attempts
                LearningStoreJob   job   = LStore.CreateJob();
                LearningStoreQuery query = LStore.CreateQuery(
                    Schema.MyAttemptsAndPackages.ViewName);
                query.AddCondition(Schema.MyAttemptsAndPackages.PackageId,
                                   LearningStoreConditionOperator.Equal, packageId);
                query.AddCondition(Schema.MyAttemptsAndPackages.AttemptId,
                                   LearningStoreConditionOperator.NotEqual, null);
                query.AddColumn(Schema.MyAttemptsAndPackages.AttemptId);
                query.AddSort(Schema.MyAttemptsAndPackages.AttemptId,
                              LearningStoreSortDirection.Ascending);
                job.PerformQuery(query);
                DataTable             dataTable         = job.Execute <DataTable>();
                AttemptItemIdentifier previousAttemptId = null;

                // loop once for each attempt on this package
                foreach (DataRow dataRow in dataTable.Rows)
                {
                    // set <attemptId> to the ID of this attempt
                    AttemptItemIdentifier attemptId;
                    LStoreHelper.CastNonNull(dataRow["AttemptId"], out attemptId);

                    // if <attemptId> is a duplicate attempt ID, skip it; note that the query
                    // results are sorted by attempt ID (see above)
                    if ((previousAttemptId != null) &&
                        (previousAttemptId.GetKey() == attemptId.GetKey()))
                    {
                        continue;
                    }

                    // delete this attempt
                    StoredLearningSession.DeleteAttempt(LStore, attemptId);

                    // continue to the next attempt
                    previousAttemptId = attemptId;
                }

                // delete the package
                PStore.DeletePackage(packageId);

                // add the package ID to the list of deleted packages
                deleted.Add(id);
            }

            // the operation was successful, and there are no messages to
            // display to the user, so close the dialog
            CloseDialogScript.Visible = true;
        }
        catch (Exception ex)
        {
            // an unexpected error occurred -- display a generic message that
            // doesn't include the exception message (since that message may
            // include sensitive information), and write the exception message
            // to the event log
            ErrorIntro.Visible   = true;
            ErrorMessage.Visible = true;
            ErrorMessage.Controls.Add(new System.Web.UI.LiteralControl(
                                          Server.HtmlEncode("A serious error occurred.  Please contact your system administrator.  More information has been written to the server event log.")));
            LogEvent(System.Diagnostics.EventLogEntryType.Error,
                     "An exception occurred while deleting a package:\n\n{0}\n\n", ex.ToString());
        }

        // update the buttons
        DeletePackagesButton.Visible = false;
        CloseButton.Text             = "OK";

        // set the hidden form element PackagesSuccessfullyDeleted to a
        // comma-separated list of IDs of packages that were successfully
        // deleted, and enable the client-side script that communicates this
        // information to the parent page
        PackagesSuccessfullyDeleted.Value = String.Join(",", deleted.ToArray());
        UpdateParentPageScript.Visible    = true;
    }
Beispiel #23
0
        SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]   // it's not worth changing this now
        public void ProcessPageLoad(PackageStore packageStore,
                                    GetSessionTitle getSessionTitle,
                                    TryGetViewInfo TryGetViewInfo,
                                    TryGetAttemptInfo TryGetAttemptInfo,
                                    AppendContentFrameDetails appendContentFrameDetails,
                                    RegisterError registerError,
                                    GetErrorInfo getErrorInfo,
                                    ProcessSessionEnd ProcessSessionEnd,
                                    ProcessViewRequest ProcessViewRequest,
                                    GetFramesetMsg getFramesetMsg,  // messages that appear that are unique to different framesets
                                    bool isPostBack)
        {
            try
            {
                RegisterError = registerError;
                GetErrorInfo = getErrorInfo;
                AppendContentFrameDetails = appendContentFrameDetails;
                GetFramesetMsg = getFramesetMsg;

                m_getSessionTitle = getSessionTitle;
                m_isPostedPage = isPostBack;

                AttemptItemIdentifier attemptId;
                SessionView view;
                LoadContentFrame = true;
                ActivityHasChanged = false;
                
                if (!TryGetViewInfo(false, out view))
                {
                    WriteError(ResHelper.GetMessage(IUDICO.TestingSystem.Localization.getMessage("FRM_ViewNotSupportedMsg")));
                    return;
                }

                switch (view)
                {
                    case SessionView.Execute:
                        {
                            if (!TryGetAttemptInfo(false, out attemptId))
                                return;

                            Session = new StoredLearningSession(view, attemptId, packageStore);
                            if (!ProcessViewRequest(view, Session))
                                return;

                            // If the session has ended, allow the application to deal with it.
                            ProcessSessionEnd(Session, ref m_sessionEndedMsgTitle, ref m_sessionEndedMsg);
                        }
                        break;
                    case SessionView.Review:
                        {
                            if (!TryGetAttemptInfo(false, out attemptId))
                                return;

                            Session = new StoredLearningSession(view, attemptId, packageStore);
                            // Do not set logging options in review view.

                            if (!ProcessViewRequest(view, Session))
                                return;
                        }
                        break;
                    case SessionView.RandomAccess:
                        {
                            // Note: RandomAccess is not supported in BWP, however that would have been caught before 
                            // displaying this frame.
                            if (!TryGetAttemptInfo(false, out attemptId))
                                return;

                            Session = new StoredLearningSession(view, attemptId, packageStore);
                            // Do not set logging options in random access view.

                            if (!ProcessViewRequest(view, Session))
                                return;

                            // Move to the first activity with a resource.
                            MoveToNextActivity(Session);
                        }
                        break;
                    default:
                        WriteError(ResHelper.GetMessage(IUDICO.TestingSystem.Localization.getMessage("FRM_ViewNotSupportedMsg")));
                        return;
                }

                // If the page is posted, process posted data. Remember that all posted data should be considered hostile! 
                // Note that if the session has already ended, then none of the posted data is saved or processed.
                if (isPostBack && !SessionIsEnded)
                {
                    // Process any datamodel changes before doing any navigation. This does not save any data.
                    ProcessDataModelValues(Request.Form[HiddenFieldNames.DataModel], Request.Form[HiddenFieldNames.ObjectiveIdMap]);


                    // Assume we do not have to reload the content frame
                    ActivityHasChanged = false;
                    LoadContentFrame = false;

                    // if the view requires more data, get it
                    if ((Session.View == SessionView.Review) || (Session.View == SessionView.RandomAccess))
                    {
                        // Get the current activity from the posted data and set the session to that activity
                        string strActivityId = Request.Form[HiddenFieldNames.ActivityId];
                        long activityId;
                        if (String.IsNullOrEmpty(strActivityId)
                                || !long.TryParse(strActivityId, out activityId))
                        {
                            WriteError(ResHelper.GetMessage(IUDICO.TestingSystem.Localization.getMessage("HID_InvalidActivityId"), strActivityId));
                        }
                        else
                        {
                            MoveToActivity(Session, activityId);
                        }
                    }

                    // Find out what the commands are and do them.
                    m_saveOnly = true;
                    ICollection<CommandInfo> commands = GetCommands();
                    foreach (CommandInfo cmdInfo in commands)
                    {
                        switch (cmdInfo.Command)
                        {
                            case Commands.DoNext:
                                {
                                    if (!Session.HasCurrentActivity || !ProcessNavigationRequests(Session))
                                    {
                                        if (Session.IsMoveToNextValid())
                                        {
                                            MoveToNextActivity(Session);
                                            ActivityHasChanged = true;
                                            LoadContentFrame = true;
                                        }
                                    }
                                    else
                                    {
                                        ActivityHasChanged = true;
                                        LoadContentFrame = true;
                                    }

                                    if (!ActivityHasChanged)
                                    {
                                        // Moving to the next activity is not valid. It's possible that when the current
                                        // activity was unloaded, it exited or suspended itself. If that's the case, we 
                                        // try to reactivate it. Note this causes the attempt count on the activity to 
                                        // increment, so on "poorly" written content, the user may not see their data 
                                        // anymore.
                                        ActivateCurrentActivity();
                                        WriteError(ResHelper.Format(GetFramesetMsg(FramesetStringId.MoveToNextFailedHtml), ThemeFolderPath), true);
                                        
                                    }
                                    m_saveOnly = false;
                                }
                                break;
                            case Commands.DoPrevious:
                                {

                                    if (!Session.HasCurrentActivity || !ProcessNavigationRequests(Session))
                                    {
                                        if (Session.IsMoveToPreviousValid())
                                        {
                                            MoveToPreviousActivity(Session);
                                            ActivityHasChanged = true;
                                            LoadContentFrame = true;
                                        }
                                    }
                                    else
                                    {
                                        ActivityHasChanged = true;
                                        LoadContentFrame = true;
                                    }

                                    if (!ActivityHasChanged)
                                    {

                                        // Moving to the previous activity is not valid. It's possible that when the current
                                        // activity was unloaded, it exited or suspended itself. If that's the case, we 
                                        // try to reactivate it. Note this causes the attempt count on the activity to 
                                        // increment, so on "poorly" written content, the user may not see their data 
                                        // anymore.
                                        ActivateCurrentActivity();
                                        WriteError(ResHelper.Format(GetFramesetMsg(FramesetStringId.MoveToPreviousFailedHtml), ThemeFolderPath), true);
                                    }
                                    m_saveOnly = false;
                                }
                                break;
                            case Commands.DoChoice:
                                {
                                    // This command is used to navigate to activities, primarily from either within a link in an
                                    // error page, or the submit page returning to the current activity. This command does not 
                                    // create a new attempt if the requested activity is already the current activity.

                                    // Requesting to move to a specific activity. The cmdData will include a numeric activity id.
                                    string cmdData = cmdInfo.CommandData;
                                    long activityId;
                                    if (long.TryParse(cmdData, out activityId))
                                    {
                                        // If the requested activity is the current activity, then do not do the navigation.
                                        // We skip it because moving to the activity basically exits the current attempt and creates
                                        // a new one and in this case, that is not the desired behavior. 
                                        // That new one also increments the attempt count. If we don't do the move, we 
                                        // pretend it was done. This will force the content frame to be reloaded with the current 
                                        // activity.
                                        if (IsCurrentActiveActivity(activityId))
                                        {
                                            ActivityHasChanged = true;
                                            LoadContentFrame = true;
                                        }
                                        else
                                        {
                                            // If there is no current activity, or if any navigation requests did not 
                                            // result in a move, then continue with the choice.
                                            if (!Session.HasCurrentActivity || !ProcessNavigationRequests(Session))
                                            {
                                                if (Session.IsMoveToActivityValid(activityId))
                                                {
                                                    MoveToActivity(Session, activityId);
                                                    ActivityHasChanged = true;
                                                    LoadContentFrame = true;
                                                }
                                            }
                                            else
                                            {
                                                ActivityHasChanged = true;
                                                LoadContentFrame = true;
                                            }
                                        }
                                    }

                                    if (!ActivityHasChanged)
                                    {
                                        // Moving to the selected activity is not valid. It's possible that when the current
                                        // activity was unloaded, it exited or suspended itself. If that's the case, we 
                                        // try to reactivate it. Note this causes the attempt count on the activity to 
                                        // increment, so on "poorly" written content, the user may not see their data 
                                        // anymore.

                                        ActivateCurrentActivity();
                                        WriteError(ResHelper.Format(GetFramesetMsg(FramesetStringId.MoveToActivityFailedHtml), ThemeFolderPath), true);
                                    }
                                    m_saveOnly = false;
                                }
                                break;
                            case Commands.DoTocChoice:
                                {
                                    // This command is used to navigate to activities in response to a user selecting a node
                                    // in the TOC. In this case, even if the current activity is the activity that is requested,
                                    // then a MoveToActivity() is requested. This will cause the attempt count on the activity
                                    // to be incremented and the RTE to be reinitialized. This may be a surprise to the user, but 
                                    // is a requirement of the SCORM 2004 conformance tests.

                                    // If the selected page is the submit page (either in Execute or RandomAccess views), then
                                    // display the message and don't ask the session to move to a new activity.

                                    string cmdData = cmdInfo.CommandData;
                                    if (String.CompareOrdinal(cmdData, SubmitId) == 0)
                                    {
                                        // Requesting submit page. Do not change the current activity, but mark it as changed so that 
                                        // it appears to the user that it has changed.
                                        ActivityHasChanged = true;
                                        LoadContentFrame = true;
                                        string title = GetFramesetMsg(FramesetStringId.SubmitPageTitleHtml);
                                        string message;
                                        string saveBtn = GetFramesetMsg(FramesetStringId.SubmitPageSaveButtonHtml);
                                        if (Session.HasCurrentActivity)
                                            message = GetFramesetMsg(FramesetStringId.SubmitPageMessageHtml);
                                        else
                                            message = GetFramesetMsg(FramesetStringId.SubmitPageMessageNoCurrentActivityHtml);
                                        WriteSubmitPage(title, message, saveBtn);
                                    }
                                    else
                                    {
                                        // Requesting to move to a specific activity. The cmdData will include a numeric activity id.

                                        long activityId;
                                        if (long.TryParse(cmdData, out activityId))
                                        {
                                            // If there is no current activity, or if any navigation requests did not 
                                            // result in a move, then continue with the choice.
                                            if (!Session.HasCurrentActivity || !ProcessNavigationRequests(Session))
                                            {
                                                if (Session.IsMoveToActivityValid(activityId))
                                                {
                                                    MoveToActivity(Session, activityId);
                                                    ActivityHasChanged = true;
                                                    LoadContentFrame = true;
                                                }
                                            }
                                            else
                                            {
                                                ActivityHasChanged = true;
                                                LoadContentFrame = true;
                                            }
                                        }
                                    }

                                    if (!ActivityHasChanged)
                                    {
                                        // Moving to the selected activity is not valid. It's possible that when the current
                                        // activity was unloaded, it exited or suspended itself. If that's the case, we 
                                        // try to reactivate it. Note this causes the attempt count on the activity to 
                                        // increment, so on "poorly" written content, the user may not see their data 
                                        // anymore.

                                        ActivateCurrentActivity();
                                        WriteError(ResHelper.Format(GetFramesetMsg(FramesetStringId.MoveToActivityFailedHtml), ThemeFolderPath), true);
                                    }
                                    m_saveOnly = false;
                                }
                                break;
                            case Commands.DoIsChoiceValid:
                                {
                                    string activityKey = cmdInfo.CommandData;
                                    bool isValid = false;
                                    if (!String.IsNullOrEmpty(activityKey))
                                    {
                                        isValid = Session.IsMoveToActivityValid(activityKey);
                                    }
                                    m_isNavValidResponse = new IsNavValidResponseData(Commands.DoIsChoiceValid, activityKey, isValid);
                                    m_saveOnly = false;
                                }
                                break;
                            case Commands.DoIsNavigationValid:
                                {
                                    string navCommand = cmdInfo.CommandData;
                                    if (!String.IsNullOrEmpty(navCommand))
                                    {
                                        bool isValid = false;
                                        if (navCommand == Commands.DoNext)
                                        {
                                            isValid = Session.IsMoveToNextValid();
                                        }
                                        else if (navCommand == Commands.DoPrevious)
                                        {
                                            isValid = Session.IsMoveToPreviousValid();
                                        }
                                        m_isNavValidResponse = new IsNavValidResponseData(Commands.DoIsNavigationValid, navCommand, isValid);
                                    }
                                    m_saveOnly = false;
                                }
                                break;
                            case Commands.DoSave:
                                {
                                    // Do nothing. The information will be saved since the page was posted.
                                }
                                break;
                            case Commands.DoTerminate: // end the current activity
                                {
                                    try
                                    {
                                        if (Session.View == SessionView.Execute)
                                        {
                                            // Keep track of state before calling ProcessNavigationRequests so that we can 
                                            // detect if the call changes it in a way that requires reloading the content frame.
                                            long activityBeforeNavigation = Session.CurrentActivityId;
                                            int activityAttemptCount = Session.CurrentActivityDataModel.ActivityAttemptCount;

                                            LearningSession session = Session;
                                            
                                            if (session.HasCurrentActivity)
                                                session.ProcessNavigationRequests();

                                            // The activity has changed if...
                                            //  ... the session now does not have a current activity (since it did before we did the ProcessNavRequests call, OR
                                            //  ... the session's current activity is not activity anymore (since it was before the call), OR
                                            //  ... the session's activity id has changed
                                            //  ... the session's activity id has not changed, but the attempt count has
                                            
                                            if (!session.HasCurrentActivity)
                                            {
                                                ActivityHasChanged = true;
                                                LoadContentFrame = true;
                                            }
                                            else if ((session.View == SessionView.Execute) && (!Session.CurrentActivityIsActive)) 
                                            {
                                                // In Execute view, it started as active or would have thrown an exception.
                                                ActivityHasChanged = true;

                                                // do not load content frame, as that causes messages to flash while switching activities
                                                LoadContentFrame = false;   
                                            }
                                            else if (activityBeforeNavigation != session.CurrentActivityId)
                                            {
                                                // The current activity has changed.
                                                ActivityHasChanged = true;
                                                LoadContentFrame = true;
                                            }
                                            else if ((activityBeforeNavigation == session.CurrentActivityId) 
                                                       && (activityAttemptCount != session.CurrentActivityDataModel.ActivityAttemptCount))
                                            {
                                                // The activity has not changed, but the attempt count has.
                                                ActivityHasChanged = true;
                                                LoadContentFrame = true;
                                            }
                                            else
                                            {
                                                // In all other cases, it has not changed
                                                ActivityHasChanged = false;
                                                LoadContentFrame = false;
                                            }
                                        }
                                        else if ((Session.View == SessionView.Review) || (Session.View == SessionView.RandomAccess))
                                        {
                                            // The activity has changed simply by calling this. This allows the client RTE to reinitialize and behave 
                                            // as if navigation has happened.
                                            ActivityHasChanged = true;
                                            LoadContentFrame = true;
                                        }
                                    }
                                    catch (SequencingException ex)
                                    {
                                        WriteError(ResHelper.GetMessage(IUDICO.TestingSystem.Localization.getMessage("HID_TerminateFailed"), HttpUtility.HtmlEncode(ex.Message)));
                                    }
                                    m_saveOnly = false;
                                }
                                break;
                            case Commands.DoSubmit:
                                {
                                    // Submit the attempt -- meaning, do an ExitAll
                                    if (Session.View == SessionView.Execute)
                                    {
                                        if (Session.HasCurrentActivity)
                                        {
                                            ProcessNavigationRequests(Session);
                                        }
                                        Session.Exit();
                                    }
                                    else if (Session.View == SessionView.RandomAccess)
                                    {
                                        // This may also be a request to end grading (for SLK), in which case 
                                        // we just set a flag, get the right strings to display and call it done
                                        SessionIsEnded = true;
                                        ProcessSessionEnd(Session, ref m_sessionEndedMsgTitle, ref m_sessionEndedMsg);
                                    }

                                    ActivityHasChanged = true;
                                    LoadContentFrame = true;
                                    m_saveOnly = false;
                                }
                                break;
                        }
                    }
                }
                else
                {
                    // Is this the first page load, as part of frameset? (Some hidden values are only rendered in this case.)
                    string param = Request.QueryString[FramesetQueryParameter.Init];
                    if (!String.IsNullOrEmpty(param))
                    {
                        m_isFramesetInitialization = true;
                    }
                }

                // If this was not simply a save operation and there is no current activity, then display a message
                // asking the user to select one.
                if (!m_saveOnly && !Session.HasCurrentActivity)
                {
                    RegisterError(GetFramesetMsg(FramesetStringId.SelectActivityTitleHtml), 
                                   GetFramesetMsg(FramesetStringId.SelectActivityMessageHtml), true);
                }

                // In Execute view, ProcessSessionEnd may write to the database and change state of data related to the attempt.
                // Therefore, session changes must be written in the same transation as the session end changes.
                TransactionOptions transactionOptions = new TransactionOptions();
                transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.Serializable;
                using (LearningStoreTransactionScope scope =
                    new LearningStoreTransactionScope(transactionOptions))
                {
                    if (!SessionIsReadOnly)
                    {
                        // Save all changes
                        Session.CommitChanges();
                    }

                    if (Session.View == SessionView.Execute)
                    {
                        // The rollup and/or sequencing process may have changed the state of the attempt. If so, there are some cases
                        // that cannot continue so show an error message. Allow the application to process this, since the messages are 
                        // different.
                        ProcessSessionEnd(Session, ref m_sessionEndedMsgTitle, ref m_sessionEndedMsg);
                    }

                    // finish the transaction
                    scope.Complete();
                }
            
                InitHiddenControlInfo();

                m_pageLoadSuccessful = true;
            }
            catch (ThreadAbortException)
            {
                // Do nothing -- thread is leaving.
                throw;
            }
            catch (Exception)
            {
                m_pageLoadSuccessful = false;
                throw;
            }
        }