boca: Add access code to be part of the session payload.
This allows display access code in teacher UI so that student can use the code to join a class session. UX mock: http://shortn/_BpugcftImn BocaAppBrowserProducerTest.* Test: unit tested. BocaAppPageHandlerTest.GetSessionWithFullInputTest Bug: b:374372602 Change-Id: Ia61582b49364e69c36b6d0949819f424f60709c4 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5938901 Reviewed-by: Benjamin Zielinski <bzielinski@google.com> Commit-Queue: April Zhou <aprilzhou@google.com> Reviewed-by: Alex Gough <ajgo@chromium.org> Cr-Commit-Position: refs/heads/main@{#1372980}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
f62c540a9f
commit
ed016cd505
ash/webui/boca_ui
chrome/test/data/webui/chromeos/boca_ui
chromeos/ash/components/boca/session_api
@ -118,12 +118,18 @@ mojom::ConfigPtr SessionConfigProtoToMojom(::boca::Session* session) {
|
||||
seconds +
|
||||
static_cast<double>(nanos) / base::Time::kNanosecondsPerSecond);
|
||||
}
|
||||
|
||||
std::string access_code;
|
||||
if (session->has_join_code()) {
|
||||
access_code = session->join_code().code();
|
||||
}
|
||||
|
||||
return mojom::Config::New(
|
||||
// Nanos are not used throughout session lifecycle so it's
|
||||
// safe to only parse seconds.
|
||||
base::Seconds(session->duration().seconds()), start_time,
|
||||
std::move(teacher), std::move(students), std::move(on_task_config),
|
||||
std::move(caption_config));
|
||||
std::move(caption_config), access_code);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@ -411,6 +417,11 @@ void BocaAppHandler::OnConsumerActivityUpdated(
|
||||
OnStudentActivityUpdated(std::move(result));
|
||||
}
|
||||
|
||||
void BocaAppHandler::OnSessionStarted(const std::string& session_id,
|
||||
const ::boca::UserIdentity& producer) {
|
||||
UpdateSessionConfig();
|
||||
}
|
||||
|
||||
void BocaAppHandler::OnSessionEnded(const std::string& session_id) {
|
||||
OnSessionConfigUpdated(
|
||||
mojom::SessionResult::NewError(mojom::GetSessionError::kEmpty));
|
||||
|
@ -76,10 +76,9 @@ class BocaAppHandler : public mojom::PageHandler,
|
||||
// BocaSessionManager::Observer
|
||||
void OnConsumerActivityUpdated(
|
||||
const std::map<std::string, ::boca::StudentStatus>& activities) override;
|
||||
// When session start, UI is already most update to date, do
|
||||
// not handle the event
|
||||
|
||||
void OnSessionStarted(const std::string& session_id,
|
||||
const ::boca::UserIdentity& producer) override {}
|
||||
const ::boca::UserIdentity& producer) override;
|
||||
void OnSessionEnded(const std::string& session_id) override;
|
||||
void OnBundleUpdated(const ::boca::Bundle& bundle) override;
|
||||
void OnSessionCaptionConfigUpdated(
|
||||
|
@ -257,7 +257,7 @@ TEST_F(BocaAppPageHandlerTest, CreateSessionWithFullInput) {
|
||||
|
||||
const auto config = mojom::Config::New(
|
||||
session_duration, std::nullopt, nullptr, std::move(students),
|
||||
GetCommonTestLockOnTaskConfig(), GetCommonCaptionConfig());
|
||||
GetCommonTestLockOnTaskConfig(), GetCommonCaptionConfig(), "");
|
||||
// Page handler callback.
|
||||
base::test::TestFuture<base::expected<std::unique_ptr<::boca::Session>,
|
||||
google_apis::ApiErrorCode>>
|
||||
@ -391,7 +391,7 @@ TEST_F(BocaAppPageHandlerTest, CreateSessionWithCritialInputOnly) {
|
||||
const auto config = mojom::Config::New(
|
||||
session_duration, std::nullopt, nullptr,
|
||||
std::vector<mojom::IdentityPtr>{}, mojom::OnTaskConfigPtr(nullptr),
|
||||
mojom::CaptionConfigPtr(nullptr));
|
||||
mojom::CaptionConfigPtr(nullptr), "");
|
||||
|
||||
::boca::UserIdentity teacher;
|
||||
teacher.set_gaia_id(kGaiaId);
|
||||
@ -450,6 +450,9 @@ TEST_F(BocaAppPageHandlerTest, GetSessionWithFullInputTest) {
|
||||
teacher->set_gaia_id("000");
|
||||
teacher->set_photo_url("cdn://s");
|
||||
|
||||
auto* access_code = session->mutable_join_code();
|
||||
access_code->set_code("testCode");
|
||||
|
||||
auto* student_groups_1 =
|
||||
session->mutable_roster()->mutable_student_groups()->Add();
|
||||
student_groups_1->set_title(kMainStudentGroupName);
|
||||
@ -495,6 +498,7 @@ TEST_F(BocaAppPageHandlerTest, GetSessionWithFullInputTest) {
|
||||
EXPECT_EQ("000", result->teacher->id);
|
||||
EXPECT_EQ("cdn://s", result->teacher->photo_url->spec());
|
||||
|
||||
EXPECT_EQ("testCode", result->access_code);
|
||||
EXPECT_EQ(true, result->caption_config->session_caption_enabled);
|
||||
EXPECT_EQ(true, result->caption_config->session_translation_enabled);
|
||||
|
||||
@ -1331,6 +1335,18 @@ TEST_F(BocaAppPageHandlerTest, RemoveStudentWithNonActiveSession) {
|
||||
EXPECT_EQ(mojom::RemoveStudentError::kInvalid, future_1.Get().value());
|
||||
}
|
||||
|
||||
TEST_F(BocaAppPageHandlerTest, OnSessionSessionStartedSucceed) {
|
||||
auto session = GetCommonActiveSessionProto();
|
||||
EXPECT_CALL(*session_manager(), GetCurrentSession())
|
||||
.WillOnce(Return(&session));
|
||||
base::test::TestFuture<mojom::SessionResultPtr> future;
|
||||
boca_app_handler()->SetSessionConfigInterceptorCallbackForTesting(
|
||||
future.GetCallback());
|
||||
boca_app_handler()->OnSessionStarted(std::string(), ::boca::UserIdentity());
|
||||
auto result = future.Take();
|
||||
ASSERT_TRUE(result->is_config());
|
||||
}
|
||||
|
||||
TEST_F(BocaAppPageHandlerTest, OnSessionEndedSucceed) {
|
||||
base::test::TestFuture<mojom::SessionResultPtr> future;
|
||||
boca_app_handler()->SetSessionConfigInterceptorCallbackForTesting(
|
||||
|
@ -60,6 +60,9 @@ struct Config{
|
||||
array<Identity> students;
|
||||
OnTaskConfig on_task_config;
|
||||
CaptionConfig caption_config;
|
||||
// Strings allow consumer to type and join a session. Will be alphabetic
|
||||
// characters.
|
||||
string? access_code;
|
||||
};
|
||||
|
||||
struct CaptionConfig {
|
||||
|
@ -95,6 +95,7 @@ export declare interface SessionConfig {
|
||||
teacher?: Identity;
|
||||
onTaskConfig: OnTaskConfig;
|
||||
captionConfig: CaptionConfig;
|
||||
accessCode?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -66,6 +66,7 @@ export function getSessionConfigMojomToUI(session: Config|
|
||||
}),
|
||||
},
|
||||
captionConfig: session.captionConfig,
|
||||
accessCode: session.accessCode ? session.accessCode : ''
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -111,6 +111,7 @@ class MockRemoteHandler extends PageHandlerRemote {
|
||||
email: 'teacher@gmail.com',
|
||||
photoUrl: {url: 'cdn0'},
|
||||
},
|
||||
accessCode: 'testCode',
|
||||
students: [
|
||||
{
|
||||
id: '1',
|
||||
@ -329,6 +330,7 @@ suite('ClientDelegateTest', function() {
|
||||
{id: '1', name: 'cat', email: 'cat@gmail.com', photoUrl: 'cdn1'},
|
||||
{id: '2', name: 'dog', email: 'dog@gmail.com', photoUrl: 'cdn2'},
|
||||
],
|
||||
accessCode: 'testCode',
|
||||
onTaskConfig: {
|
||||
isLocked: true,
|
||||
tabs: [
|
||||
@ -379,6 +381,7 @@ suite('ClientDelegateTest', function() {
|
||||
email: 'teacher@gmail.com',
|
||||
photoUrl: {url: 'cdn0'},
|
||||
},
|
||||
accessCode: null,
|
||||
captionConfig: {
|
||||
sessionCaptionEnabled: true,
|
||||
localCaptionEnabled: true,
|
||||
@ -401,6 +404,7 @@ suite('ClientDelegateTest', function() {
|
||||
isLocked: false,
|
||||
tabs: [],
|
||||
},
|
||||
accessCode: '',
|
||||
captionConfig: {
|
||||
sessionCaptionEnabled: true,
|
||||
localCaptionEnabled: true,
|
||||
|
@ -74,6 +74,9 @@ inline constexpr char kDeviceId[] = "deviceId";
|
||||
inline constexpr char kActivity[] = "activity";
|
||||
inline constexpr char kUsers[] = "users";
|
||||
inline constexpr char kTachyonGroupId[] = "tachyonGroupId";
|
||||
inline constexpr char kJoinCode[] = "joinCode";
|
||||
inline constexpr char kJoinCodeEnabled[] = "enabled";
|
||||
inline constexpr char kCode[] = "code";
|
||||
|
||||
inline constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
|
||||
net::DefineNetworkTrafficAnnotation("boca_classroom_integration", R"(
|
||||
|
@ -89,6 +89,20 @@ void ParseTeacherProtoFromJson(base::Value::Dict* session_dict,
|
||||
}
|
||||
}
|
||||
|
||||
void ParseJoinCodeProtoFromJson(base::Value::Dict* session_dict,
|
||||
::boca::Session* session) {
|
||||
if (!session_dict->FindDict(kJoinCode)) {
|
||||
return;
|
||||
}
|
||||
auto* join_code = session->mutable_join_code();
|
||||
join_code->set_enabled(session_dict->FindDict(kJoinCode)
|
||||
->FindBool(kJoinCodeEnabled)
|
||||
.value_or(false));
|
||||
if (auto* ptr = session_dict->FindDict(kJoinCode)->FindString(kCode)) {
|
||||
join_code->set_code(*ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void ParseRosterProtoFromJson(base::Value::Dict* session_dict,
|
||||
::boca::Session* session) {
|
||||
auto* roster_dict = session_dict->FindDict(kRoster);
|
||||
@ -300,6 +314,8 @@ std::unique_ptr<::boca::Session> GetSessionProtoFromJson(std::string json,
|
||||
|
||||
ParseTeacherProtoFromJson(session_dict, session.get());
|
||||
|
||||
ParseJoinCodeProtoFromJson(session_dict, session.get());
|
||||
|
||||
ParseRosterProtoFromJson(session_dict, session.get());
|
||||
|
||||
ParseSessionConfigProtoFromJson(session_dict, session.get(), is_producer);
|
||||
|
@ -24,6 +24,8 @@ namespace ash::boca {
|
||||
// Proto to Json
|
||||
void ParseTeacherProtoFromJson(base::Value::Dict* session_dict,
|
||||
::boca::Session* session);
|
||||
void ParseJoinCodeProtoFromJson(base::Value::Dict* session_dict,
|
||||
::boca::Session* session);
|
||||
void ParseRosterProtoFromJson(base::Value::Dict* session_dict,
|
||||
::boca::Session* session);
|
||||
void ParseSessionConfigProtoFromJson(base::Value::Dict* session_dict,
|
||||
|
@ -14,8 +14,9 @@
|
||||
namespace ash::boca {
|
||||
namespace {
|
||||
|
||||
// Unit test cases for proto2json conversion is covered in
|
||||
// create_session_request_unittest.cc, not duplicating here.
|
||||
// TODO(crbug.com/374364083):Refactor existing get session unit test.
|
||||
// Currently this file doesn't have full coverage for session_parser, the reset
|
||||
// is covered in get_session_request_unittest, we should move those here.
|
||||
constexpr char kFullSessionResponse[] = R"(
|
||||
{
|
||||
"startTime":{
|
||||
@ -25,6 +26,10 @@ constexpr char kFullSessionResponse[] = R"(
|
||||
"duration": {
|
||||
"seconds": 120
|
||||
},
|
||||
"joinCode":{
|
||||
"enabled":true,
|
||||
"code":"testCode"
|
||||
},
|
||||
"studentStatuses": {
|
||||
"2": {
|
||||
"state": "ADDED"
|
||||
@ -161,6 +166,13 @@ TEST_F(SessionParserTest, TestParseTeacherProtoFromJson) {
|
||||
EXPECT_EQ("1", session_partial->teacher().gaia_id());
|
||||
}
|
||||
|
||||
TEST_F(SessionParserTest, TestParseJoinCodeProtoFromJson) {
|
||||
ParseJoinCodeProtoFromJson(session_dict_full->GetIfDict(),
|
||||
session_full.get());
|
||||
EXPECT_TRUE(session_full->join_code().enabled());
|
||||
EXPECT_EQ("testCode", session_full->join_code().code());
|
||||
}
|
||||
|
||||
TEST_F(SessionParserTest, TestParseRosterProtoFromJson) {
|
||||
ParseRosterProtoFromJson(session_dict_full->GetIfDict(), session_full.get());
|
||||
ASSERT_EQ(2, session_full->roster().student_groups()[0].students().size());
|
||||
|
Reference in New Issue
Block a user