Skip to content

Commit

Permalink
Merge branch 'Simon-Initiative:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
dtiwarATS authored Sep 11, 2024
2 parents 26262c5 + 9f6dff7 commit 2c8baab
Show file tree
Hide file tree
Showing 52 changed files with 1,495 additions and 1,564 deletions.
2 changes: 2 additions & 0 deletions assets/src/apps/Components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ import { globalStore } from 'state/store';
import { VideoPlayer } from '../components/video_player/VideoPlayer';
import { OfflineDetector } from './OfflineDetector';
import ActivityBank from './bank/ActivityBank';
import Bibliography from './bibliography/Bibliography';
import { References } from './bibliography/References';

registerApplication('Bibliography', Bibliography, globalStore);
registerApplication('ModalDisplay', ModalDisplay, globalStore);
registerApplication('DarkModeSelector', DarkModeSelector);
registerApplication('PaginationControls', PaginationControls, globalStore);
Expand Down
33 changes: 33 additions & 0 deletions assets/src/hooks/evaluate_mathjax_expressions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// this hook is used to evaluate MathJax expressions in the page
// just after the page is mounted and the websocket connection is established.

export const EvaluateMathJaxExpressions = {
mounted() {
const elements = document.querySelectorAll('.formula, .formula-inline');

const getGlobalLastPromise = () => {
/* istanbul ignore next */
let lastPromise = window?.MathJax?.startup?.promise;
/* istanbul ignore next */
if (!lastPromise) {
console.info('NO LAST PROMISE');
typeof jest === 'undefined' &&
console.warn(
'Load the MathJax script before this one or unpredictable rendering might occur.',
);
lastPromise = Promise.resolve();
}
return lastPromise;
};

const setGlobalLastPromise = (promise: Promise<any>) => {
window.MathJax.startup.promise = promise;
};

let lastPromise = getGlobalLastPromise();
lastPromise = lastPromise.then(() =>
window.MathJax.typesetPromise(Array.from(elements) as HTMLElement[]),
);
setGlobalLastPromise(lastPromise);
},
};
2 changes: 2 additions & 0 deletions assets/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { DateTimeLocalInputListener } from './datetimelocal_input_listener';
import { DragSource, DropTarget } from './dragdrop';
import { EmailList } from './email_list';
import { EndDateTimer } from './end_date_timer';
import { EvaluateMathJaxExpressions } from './evaluate_mathjax_expressions';
import { GraphNavigation } from './graph';
import { HierarchySelector } from './hierarchy_selector';
import { InputAutoSelect } from './input_auto_select';
Expand Down Expand Up @@ -79,4 +80,5 @@ export const Hooks = {
Countdown,
CountdownTimer,
EndDateTimer,
EvaluateMathJaxExpressions,
};
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ defmodule Oli.Activities.Transformers.VariableSubstitution.RestImpl do

{:ok, %HTTPoison.Response{}} ->
{:error, "Error retrieving the payload"}

{:error, reason} ->
{:error, reason}
end
end
end
31 changes: 15 additions & 16 deletions lib/oli/delivery/attempts/manual_grading.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,21 @@ defmodule Oli.Delivery.Attempts.ManualGrading do
ActivityAttempt
}

def count_submitted_attempts(%Section{} = section) do
case browse_submitted_attempts(
section,
%Paging{limit: 1, offset: 0},
%Sorting{field: :date_submitted, direction: :asc},
%BrowseOptions{
user_id: nil,
activity_id: nil,
text_search: nil,
page_id: nil,
graded: nil
}
) do
[] -> 0
[item] -> item.total_count
end
def has_submitted_attempts(%Section{id: section_id}) do
query =
ActivityAttempt
|> join(:left, [aa], resource_attempt in ResourceAttempt,
on: aa.resource_attempt_id == resource_attempt.id
)
|> join(:left, [_, resource_attempt], ra in ResourceAccess,
on: resource_attempt.resource_access_id == ra.id
)
|> where(
[aa, _resource_attempt, resource_access],
resource_access.section_id == ^section_id and aa.lifecycle_state == :submitted
)

Repo.exists?(query)
end

@doc """
Expand Down
15 changes: 12 additions & 3 deletions lib/oli/delivery/attempts/page_lifecycle.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ defmodule Oli.Delivery.Attempts.PageLifecycle do
"""

alias Oli.Repo

use Appsignal.Instrumentation.Decorators
import Oli.Delivery.Attempts.Core
alias Oli.Accounts.User
alias Oli.Delivery.Sections
Expand Down Expand Up @@ -47,6 +47,7 @@ defmodule Oli.Delivery.Attempts.PageLifecycle do
`{:error, {:no_more_attempts}}` if no more attempts are present
"""
@decorate transaction_event("PageLifeCycle: start")
def start(
revision_slug,
section_slug,
Expand Down Expand Up @@ -117,6 +118,7 @@ defmodule Oli.Delivery.Attempts.PageLifecycle do
{:ok, {:in_progress | :revised, AttemptState.t()}}
| {:ok, {:not_started, HistorySummary.t()}}
| {:error, any}
@decorate transaction_event("PageLifeCycle: visit")
def visit(
page_revision,
section_slug,
Expand All @@ -130,8 +132,10 @@ defmodule Oli.Delivery.Attempts.PageLifecycle do
update_latest_visited_page(section_slug, user.id, page_revision.resource_id)

{graded, latest_resource_attempt} =
get_latest_resource_attempt(page_revision.resource_id, section_slug, user.id)
|> handle_type_transitions(page_revision)
Appsignal.instrument("PageLifeCycle: get_latest_resource_attempt", fn ->
get_latest_resource_attempt(page_revision.resource_id, section_slug, user.id)
|> handle_type_transitions(page_revision)
end)

publication_id =
Publishing.get_publication_id_for_resource(section_slug, page_revision.resource_id)
Expand All @@ -158,6 +162,7 @@ defmodule Oli.Delivery.Attempts.PageLifecycle do
end)
end

@decorate transaction_event("PageLifeCycle: update_latest_visited_page")
defp update_latest_visited_page(section_slug, user_id, resource_id) do
Sections.get_enrollment(section_slug, user_id)
|> Sections.update_enrollment(%{most_recently_visited_resource_id: resource_id})
Expand All @@ -178,6 +183,7 @@ defmodule Oli.Delivery.Attempts.PageLifecycle do
`{:error, {:not_found}}`
"""
@decorate transaction_event("PageLifeCycle: review")
def review(resource_attempt_guid) do
Repo.transaction(fn ->
case get_resource_attempt_by(attempt_guid: resource_attempt_guid) do
Expand Down Expand Up @@ -210,6 +216,7 @@ defmodule Oli.Delivery.Attempts.PageLifecycle do
`{:error, {:already_submitted}}`
"""
@decorate transaction_event("PageLifeCycle: finalize")
def finalize(section_slug, resource_attempt_guid, datashop_session_id) do
result =
Repo.transaction(fn _ ->
Expand Down Expand Up @@ -271,6 +278,7 @@ defmodule Oli.Delivery.Attempts.PageLifecycle do
its attempt guid. A user can access a resource attempt if that user is either an
instructor enrolled in that section, or the student that originated the attempt.
"""
@decorate transaction_event("PageLifeCycle: can_access_attempt")
def can_access_attempt?(resource_attempt_guid, %User{id: user_id} = user, %Section{
slug: section_slug,
id: section_id
Expand All @@ -295,6 +303,7 @@ defmodule Oli.Delivery.Attempts.PageLifecycle do
#
# 1. Use the current revision if no resource attempt is present, or if the current revision is set to "graded"
# 2. Otherwise return "graded" value of the resource attempt revision.
@decorate transaction_event("PageLifeCycle: handle_type_transitions")
defp handle_type_transitions(resource_attempt, resource_revision) do
if is_nil(resource_attempt) || resource_attempt.revision.graded === resource_revision.graded do
# There is no latest attempt, or the latest attempt revision's graded status doesn't differ from the current revisions
Expand Down
10 changes: 10 additions & 0 deletions lib/oli/delivery/attempts/page_lifecycle/graded.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ defmodule Oli.Delivery.Attempts.PageLifecycle.Graded do
Hierarchy
}

use Appsignal.Instrumentation.Decorators
alias Oli.Delivery.Settings
alias Oli.Delivery.Settings.Combined
alias Oli.Delivery.Attempts.Scoring
Expand All @@ -31,6 +32,7 @@ defmodule Oli.Delivery.Attempts.PageLifecycle.Graded do
@behaviour Lifecycle

@impl Lifecycle
@decorate transaction_event("Graded.visit")
def visit(%VisitContext{
latest_resource_attempt: latest_resource_attempt,
page_revision: page_revision,
Expand Down Expand Up @@ -73,6 +75,7 @@ defmodule Oli.Delivery.Attempts.PageLifecycle.Graded do
end

@impl Lifecycle
@decorate transaction_event("Graded.start")
def start(
%VisitContext{
page_revision: page_revision,
Expand Down Expand Up @@ -131,11 +134,13 @@ defmodule Oli.Delivery.Attempts.PageLifecycle.Graded do
end

@impl Lifecycle
@decorate transaction_event("Graded.review")
def review(%ReviewContext{} = context) do
Common.review(context)
end

@impl Lifecycle
@decorate transaction_event("Graded.finalize")
def finalize(%FinalizationContext{
resource_attempt: %ResourceAttempt{lifecycle_state: :active} = resource_attempt,
section_slug: section_slug,
Expand Down Expand Up @@ -195,6 +200,7 @@ defmodule Oli.Delivery.Attempts.PageLifecycle.Graded do

def finalize(_), do: {:error, {:already_submitted}}

@decorate transaction_event("Graded.finalize_activity_and_part_attempts")
defp finalize_activity_and_part_attempts(resource_attempt, datashop_session_id) do
case resource_attempt.revision do
# For adaptive pages, we never want to evaluate anything at finalization time
Expand Down Expand Up @@ -226,6 +232,7 @@ defmodule Oli.Delivery.Attempts.PageLifecycle.Graded do
Core.update_resource_attempt(ra, %{auto_submit_job_id: nil})
end

@decorate transaction_event("Graded.roll_up_activities_to_resource_attempt")
def roll_up_activities_to_resource_attempt(resource_attempt, %Combined{} = effective_settings) do
# It is necessary to refetch the resource attempt so that we have the latest view
# of its state, and to separately fetch the list of most recent attempts for each
Expand All @@ -252,6 +259,7 @@ defmodule Oli.Delivery.Attempts.PageLifecycle.Graded do
end
end

@decorate transaction_event("Graded.apply_evaluation")
defp apply_evaluation(
resource_attempt,
activity_attempts,
Expand Down Expand Up @@ -282,6 +290,7 @@ defmodule Oli.Delivery.Attempts.PageLifecycle.Graded do
})
end

@decorate transaction_event("Graded.apply_submission")
defp apply_submission(resource_attempt, %Combined{} = effective_settings) do
case resource_attempt.lifecycle_state do
:active ->
Expand Down Expand Up @@ -351,6 +360,7 @@ defmodule Oli.Delivery.Attempts.PageLifecycle.Graded do
ensure_valid_grade({score, out_of})
end

@decorate transaction_event("Graded.roll_up_resource_attempts_to_access")
def roll_up_resource_attempts_to_access(
%{scoring_strategy_id: scoring_strategy_id},
_section_slug,
Expand Down
12 changes: 10 additions & 2 deletions lib/oli/delivery/attempts/page_lifecycle/ungraded.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,19 @@ defmodule Oli.Delivery.Attempts.PageLifecycle.Ungraded do
in the case that the attempt was pinned to an older revision of the resource. This allows newly published
changes to the resource to be seen after a user has visited the resource previously.
"""
use Appsignal.Instrumentation.Decorators

@behaviour Lifecycle

@impl Lifecycle
@decorate transaction_event("Ungraded.visit")
def visit(
%VisitContext{
latest_resource_attempt: latest_resource_attempt,
page_revision: page_revision
} = context
) do
if is_nil(latest_resource_attempt) or latest_resource_attempt.revision_id != page_revision.id or
if is_nil(latest_resource_attempt) or
latest_resource_attempt.lifecycle_state == :evaluated do
case start(context) do
{:ok, %AttemptState{} = attempt_state} ->
Expand All @@ -47,13 +49,16 @@ defmodule Oli.Delivery.Attempts.PageLifecycle.Ungraded do
end
else
{:ok, attempt_state} =
AttemptState.fetch_attempt_state(latest_resource_attempt, page_revision)
Appsignal.instrument("Ungraded: AttemptState.fetch_attempt_state", fn ->
AttemptState.fetch_attempt_state(latest_resource_attempt, page_revision)
end)

{:ok, {:in_progress, attempt_state}}
end
end

@impl Lifecycle
@decorate transaction_event("Ungraded.finalize")
def finalize(%FinalizationContext{
resource_attempt: %ResourceAttempt{lifecycle_state: :active} = resource_attempt,
effective_settings: effective_settings
Expand Down Expand Up @@ -81,18 +86,21 @@ defmodule Oli.Delivery.Attempts.PageLifecycle.Ungraded do
{:ok,
{:finalized, Oli.Delivery.Attempts.PageLifecycle.AttemptState.t()}
| {:in_progress, Oli.Delivery.Attempts.PageLifecycle.AttemptState.t()}}
@decorate transaction_event("Ungraded.review")
def review(%ReviewContext{} = context) do
Common.review(context)
end

@impl Lifecycle
@decorate transaction_event("Ungraded.start")
def start(%VisitContext{} = context) do
{:ok, resource_attempt} = Hierarchy.create(context)

AttemptState.fetch_attempt_state(resource_attempt, context.page_revision)
|> update_progress(resource_attempt)
end

@decorate transaction_event("Ungraded.update_progress")
defp update_progress({:ok, state}, %ResourceAttempt{
resource_access_id: resource_access_id
}) do
Expand Down
2 changes: 2 additions & 0 deletions lib/oli/delivery/page/activity_context.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ defmodule Oli.Delivery.Page.ActivityContext do
@moduledoc """
Defines the context required to render an activity in delivery mode.
"""
use Appsignal.Instrumentation.Decorators

alias Oli.Delivery.Page.ModelPruner
alias Oli.Rendering.Activity.ActivitySummary
Expand All @@ -23,6 +24,7 @@ defmodule Oli.Delivery.Page.ActivityContext do
Oli.Delivery.Attempts.Core.ResourceAttempt.t(),
Oli.Resources.Revision.t()
) :: %{}
@decorate transaction_event()
def create_context_map(graded, latest_attempts, resource_attempt, page_revision, opts \\ []) do
# get a view of all current registered activity types
registrations = Activities.list_activity_registrations()
Expand Down
Loading

0 comments on commit 2c8baab

Please sign in to comment.