Skip to content

Commit ed60f9e

Browse files
checkpoint: 07-08-2025 13:08:58
1 parent 14f74bf commit ed60f9e

File tree

25 files changed

+328
-196
lines changed

25 files changed

+328
-196
lines changed

app/controllers/components/course/scholaistic_component.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,13 @@ def assistant_sidebar_items
5555
def admin_sidebar_items
5656
[
5757
{
58+
key: :scholaistic_assistants,
5859
type: :admin,
5960
icon: :chatbot,
6061
title: I18n.t('components.scholaistic.manage_assistants'),
6162
weight: 9,
62-
path: course_scholaistic_assistants_path(current_course)
63+
path: course_scholaistic_assistants_path(current_course),
64+
exact: true
6365
}
6466
]
6567
end

app/controllers/course/admin/scholaistic_settings_controller.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def confirm_link_course
1515
key = ScholaisticApiService.parse_link_course_callback_request(request, params)
1616
head :bad_request and return if key.blank?
1717

18-
@settings.update(integration_key: key) && current_course.save
18+
@settings.update(integration_key: key, last_synced_at: nil) && current_course.save
1919
end
2020

2121
def link_course
@@ -35,7 +35,7 @@ def unlink_course
3535

3636
ScholaisticApiService.unlink_course!(@settings.integration_key)
3737

38-
update_settings_and_render(integration_key: nil)
38+
update_settings_and_render(integration_key: nil, last_synced_at: nil)
3939
end
4040

4141
protected

app/controllers/course/scholaistic/assistants_controller.rb

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,22 @@ class Course::Scholaistic::AssistantsController < Course::Scholaistic::Controlle
33
def index
44
authorize! :manage_scholaistic_assistants, current_course
55

6-
@embed_src = ScholaisticApiService.embed(current_course_user, ScholaisticApiService.assistants_path)
6+
@embed_src = ScholaisticApiService.embed!(
7+
current_course_user,
8+
ScholaisticApiService.assistants_path,
9+
request.origin
10+
)
711
end
812

913
def show
1014
authorize! :read_scholaistic_assistants, current_course
1115

12-
assistant_id = params[:id]
16+
@assistant_title = ScholaisticApiService.assistant!(current_course, params[:id])[:title]
1317

14-
@assistant_title = ScholaisticApiService.assistant!(current_course, assistant_id)[:title]
15-
@embed_src = ScholaisticApiService.embed(current_course_user, ScholaisticApiService.assistant_path(assistant_id))
18+
@embed_src = ScholaisticApiService.embed!(
19+
current_course_user,
20+
ScholaisticApiService.assistant_path(params[:id]),
21+
request.origin
22+
)
1623
end
1724
end

app/controllers/course/scholaistic/scholaistic_assessments_controller.rb

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
class Course::Scholaistic::ScholaisticAssessmentsController < Course::Scholaistic::Controller
33
load_and_authorize_resource :scholaistic_assessment, through: :course, class: Course::ScholaisticAssessment.name
44

5-
before_action :sync_scholaistic_assessments!
5+
before_action :sync_scholaistic_assessments!, only: [:index, :show, :edit]
66

77
def index
88
submissions_status_hash = ScholaisticApiService.submissions!(
@@ -12,30 +12,43 @@ def index
1212

1313
@assessments_status = @scholaistic_assessments.to_h do |assessment|
1414
[assessment.id,
15-
submissions_status_hash[assessment.upstream_id]&.status ||
15+
submissions_status_hash[assessment.upstream_id]&.[](:status) ||
1616
(condition_satisfied?(assessment) ? 'unavailable' : 'open')]
1717
end
1818
end
1919

2020
def new
21-
@embed_src = ScholaisticApiService.embed(current_course_user, ScholaisticApiService.new_assessment_path)
21+
@embed_src = ScholaisticApiService.embed!(
22+
current_course_user,
23+
ScholaisticApiService.new_assessment_path,
24+
request.origin
25+
)
2226
end
2327

2428
def show
2529
upstream_id = @scholaistic_assessment.upstream_id
2630

2731
@embed_src =
2832
if can?(:update, @scholaistic_assessment)
29-
ScholaisticApiService.embed(current_course, ScholaisticApiService.edit_assessment_path(upstream_id))
33+
ScholaisticApiService.embed!(
34+
current_course_user,
35+
ScholaisticApiService.edit_assessment_path(upstream_id),
36+
request.origin
37+
)
3038
else
31-
ScholaisticApiService.embed(current_course_user, ScholaisticApiService.assessment_path(upstream_id))
39+
ScholaisticApiService.embed!(
40+
current_course_user,
41+
ScholaisticApiService.assessment_path(upstream_id),
42+
request.origin
43+
)
3244
end
3345
end
3446

3547
def edit
36-
@embed_src = ScholaisticApiService.embed(
37-
current_course,
38-
ScholaisticApiService.edit_assessment_details_path(@scholaistic_assessment.upstream_id)
48+
@embed_src = ScholaisticApiService.embed!(
49+
current_course_user,
50+
ScholaisticApiService.edit_assessment_details_path(@scholaistic_assessment.upstream_id),
51+
request.origin
3952
)
4053
end
4154

@@ -78,8 +91,9 @@ def sync_scholaistic_assessments!
7891
end.save!
7992
end
8093

81-
if response[:deleted].present?
82-
current_course.scholaistic_assessments.where(upstream_id: response[:deleted]).destroy_all
94+
if response[:deleted].present? && !current_course.scholaistic_assessments.
95+
where(upstream_id: response[:deleted]).destroy_all
96+
raise ActiveRecord::Rollback
8397
end
8498

8599
current_course.settings(:course_scholaistic_component).public_send('last_synced_at=', response[:last_synced_at])

app/controllers/course/scholaistic/submissions_controller.rb

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,23 @@ class Course::Scholaistic::SubmissionsController < Course::Scholaistic::Controll
55
before_action :sync_scholaistic_submission!, only: [:show]
66

77
def index
8-
@embed_src = ScholaisticApiService.embed(
9-
current_course_user, ScholaisticApiService.submissions_path(@scholaistic_assessment.upstream_id)
8+
@embed_src = ScholaisticApiService.embed!(
9+
current_course_user,
10+
ScholaisticApiService.submissions_path(@scholaistic_assessment.upstream_id),
11+
request.origin
1012
)
1113
end
1214

1315
def show
14-
@creator_name = ScholaisticApiService.submission!(submission_id)
16+
result = ScholaisticApiService.submission!(current_course, submission_id)
17+
head :not_found and return if result[:status] == :not_found
1518

16-
@embed_src = ScholaisticApiService.embed(
17-
current_course_user, ScholaisticApiService.submission_path(@scholaistic_assessment.upstream_id, submission_id)
19+
@creator_name = result[:creator_name]
20+
21+
@embed_src = ScholaisticApiService.embed!(
22+
current_course_user,
23+
ScholaisticApiService.submission_path(@scholaistic_assessment.upstream_id, submission_id),
24+
request.origin
1825
)
1926
end
2027

app/services/scholaistic_api_service.rb

Lines changed: 58 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -33,118 +33,95 @@ def assistant_path(assistant_id)
3333
"/assistants/#{assistant_id}"
3434
end
3535

36-
# TODO
37-
def embed(course_user, path)
38-
# connection!(course_user, :post, 'embed', body: {
39-
# key: settings(course_user.course).integration_key,
40-
# path: path
41-
# })
42-
43-
# 'https://beta.scholaistic.com/courses/1adc364a-c5cb-45f2-80b8-09fec4fc19ce/administration/assessments/6c20d164-989d-498e-b792-5f4c98a2f9f4/submissions'
44-
'https://beta.scholaistic.com/courses/1adc364a-c5cb-45f2-80b8-09fec4fc19ce/administration/assessments/6c20d164-989d-498e-b792-5f4c98a2f9f4/details'
36+
def embed!(course_user, path, origin)
37+
connection!(:post, 'embed', body: {
38+
key: settings(course_user.course).integration_key,
39+
path: path,
40+
origin: origin,
41+
upsert_course_user: course_user_upsert_payload(course_user)
42+
})
4543
end
4644

47-
# TODO
4845
def assistant!(course, assistant_id)
49-
# connection!(:get, 'assistant', query: { key: settings(course).integration_key, id: assistant_id })
46+
result = connection!(:get, 'assistant', query: { key: settings(course).integration_key, id: assistant_id })
5047

51-
{
52-
title: 'gptboy'
53-
}
48+
{ title: result[:title] }
5449
end
5550

56-
# TODO
5751
def assistants!(course)
58-
# connection!(:get, 'assistants', query: { key: settings(course).integration_key })
52+
result = connection!(:get, 'assistants', query: { key: settings(course).integration_key })
5953

60-
[{
61-
id: 'gptboy',
62-
title: 'gptboy',
63-
sidebar_title: 'gptboy'
64-
}, {
65-
id: 'gptgirl',
66-
title: 'gptgirl',
67-
sidebar_title: 'gptgirl'
68-
}]
54+
result.filter_map do |assistant|
55+
next if assistant[:activityType] != 'assistant' || !assistant[:isPublished]
56+
57+
{
58+
id: assistant[:id],
59+
title: assistant[:title],
60+
sidebar_title: assistant[:altTitle]
61+
}
62+
end
6963
end
7064

71-
# TODO
7265
def find_or_create_submission!(course_user, assessment_id)
73-
# connection!(course_user, :post, 'submission', body: {
74-
# key: settings(course_user.course).integration_key,
75-
# assessmentId: assessment_id,
76-
# upsertCourseUser: course_user_upsert_payload(course_user)
77-
# })
66+
result = connection!(:post, 'submission', body: {
67+
key: settings(course_user.course).integration_key,
68+
assessment_id: assessment_id,
69+
upsert_course_user: course_user_upsert_payload(course_user)
70+
})
7871

79-
'12345' # Example submission ID
72+
result[:id]
8073
end
8174

82-
# TODO
8375
def submission!(course, submission_id)
84-
# connection!(:get, 'submission', query: {
85-
# key: settings(course).integration_key,
86-
# id: submission_id
87-
# })
76+
result = connection!(:get, 'submission', query: {
77+
key: settings(course).integration_key,
78+
id: submission_id
79+
})
8880

8981
{
90-
creator_name: 'hamad',
91-
creator_email: '[email protected]',
92-
status: :graded
82+
creator_name: result[:creatorName],
83+
creator_email: result[:creatorEmail],
84+
status: result[:status]
9385
}
9486
rescue Excon::Error::NotFound
9587
{ status: :not_found }
9688
end
9789

98-
# TODO
9990
def submissions!(assessment_ids, course_user)
100-
# connection!(:post, 'submissions', body: {
101-
# key: settings(course_user.course).integration_key,
102-
# assessmentIds: assessment_ids,
103-
# upsertCourseUser: course_user_upsert_payload(course_user)
104-
# })
91+
result = connection!(:post, 'submissions', body: {
92+
key: settings(course_user.course).integration_key,
93+
assessment_ids: assessment_ids,
94+
upsert_course_user: course_user_upsert_payload(course_user)
95+
})
10596

106-
{
107-
'12345': {
108-
status: 'attempting',
109-
id: '12345'
110-
}
111-
}
97+
result.to_h do |assessment_id, submission|
98+
[assessment_id.to_s,
99+
status: submission[:status],
100+
id: submission[:submissionId]]
101+
end
112102
end
113103

114-
# TODO
115104
def assessments!(course)
116-
# connection!(:get, 'assessments', query: {
117-
# key: settings(course).integration_key,
118-
# lastSynced: settings(course).last_synced_at
119-
# }.compact)
105+
result = connection!(:get, 'assessments', query: {
106+
key: settings(course).integration_key,
107+
lastSynced: settings(course).last_synced_at
108+
}.compact)
120109

121110
{
122-
assessments: [
123-
{
124-
upstream_id: '12345',
125-
published: true,
126-
title: 'Sample Assessment2',
127-
description: 'This is a sample assessment for testing purposes.',
128-
start_at: Time.current.iso8601,
129-
end_at: (Time.current + 1.week).iso8601
130-
},
111+
assessments: result[:assessments].filter_map do |assessment|
112+
next if assessment[:activityType] != 'assessment'
113+
131114
{
132-
upstream_id: '67890',
133-
published: false,
134-
title: 'Draft Assessment',
135-
description: 'This assessment is still in draft mode and not yet published.',
136-
start_at: (Time.current + 1.day).iso8601
115+
upstream_id: assessment[:id],
116+
published: assessment[:isPublished],
117+
title: assessment[:title],
118+
description: assessment[:description],
119+
start_at: assessment[:startsAt],
120+
end_at: assessment[:endsAt]
137121
}
138-
# {
139-
# upstream_id: '11223',
140-
# published: true,
141-
# title: 'Upcoming Assessment',
142-
# description: 'This assessment will be available in the future.',
143-
# start_at: (Time.current + 2.days).iso8601
144-
# }
145-
],
146-
deleted: ['11223'],
147-
last_synced_at: Time.current.iso8601
122+
end,
123+
deleted: result[:deleted],
124+
last_synced_at: result[:lastSynced]
148125
}
149126
end
150127

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { ComponentType, ReactNode, Suspense } from 'react';
2+
import { Await, useLoaderData } from 'react-router-dom';
3+
4+
import LoadingIndicator from 'lib/components/core/LoadingIndicator';
5+
6+
const ScholaisticAsyncContainer = ({
7+
children,
8+
}: {
9+
children: ReactNode;
10+
}): JSX.Element => {
11+
const data = useLoaderData() as { promise: Promise<unknown> };
12+
13+
return (
14+
<Suspense fallback={<LoadingIndicator />}>
15+
<Await errorElement={<p>oopsie</p>} resolve={data.promise}>
16+
{children}
17+
</Await>
18+
</Suspense>
19+
);
20+
};
21+
22+
export const withScholaisticAsyncContainer = (
23+
Component: ComponentType,
24+
): ComponentType => {
25+
const WrappedComponent: ComponentType = (props) => (
26+
<ScholaisticAsyncContainer>
27+
<Component {...props} />
28+
</ScholaisticAsyncContainer>
29+
);
30+
31+
WrappedComponent.displayName = `withScholaisticAsyncContainer(${Component.displayName || Component.name})`;
32+
33+
return WrappedComponent;
34+
};

0 commit comments

Comments
 (0)