Conversation
概览本次变更涉及教学和员工模块的API演进。教学模块重组了课程日程响应数据结构,将课程信息和学期开始时间戳一起封装。员工模块新增三个健身分数管理的RPC方法(创建、更新、删除),并完善了相应的协议定义和OpenAPI文档。 变更详情
代码审查工作量🎯 3 (中等复杂度) | ⏱️ ~25 分钟 诗歌
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
campusapis/teaching/v1/teaching.proto (1)
203-213: GetScheduleResponse 的 data 类型变更会破坏兼容性
data从repeated ScheduleResponseCourse变成ScheduleResponseData会导致旧客户端解析失败/数据错乱(proto 与 JSON 都变了)。建议保持旧字段并新增版本化字段或升级 API 版本,避免现有调用方被破坏。🔧 兼容性修复建议(示例)
message GetScheduleResponse { int32 error = 1; string msg = 2; - ScheduleResponseData data = 3; + // 兼容旧客户端 + repeated ScheduleResponseCourse data = 3 [deprecated = true]; + // 新版结构 + ScheduleResponseData data_v2 = 4; }
🤖 Fix all issues with AI agents
In `@campusapis/fitness/v1/fitness.proto`:
- Around line 23-31: The PATCH RPC UpdateFitnessScore currently takes scalar
fields that can't represent "not provided" and risks accidental zeroing; fix by
either changing rpc UpdateFitnessScore to use PUT with a full FitnessScore
payload, or (preferred) keep PATCH but modify UpdateFitnessScoreRequest to
include a google.protobuf.FieldMask update_mask plus a single FitnessScore score
(or make scalar fields explicitly optional), update the HTTP annotation
accordingly, and ensure server-side update logic respects update_mask; apply the
same FieldMask/optional approach to the other PATCH RPCs in this proto that
suffer the same issue.
- Around line 12-19: additional_bindings for StoreFitnessScore and
UpdateFitnessScore omit body mapping, causing POST/PATCH to /fitness/score to
treat the payload as query params; update the RPC options for both
StoreFitnessScore and UpdateFitnessScore to add body: "*" inside their
additional_bindings so the /fitness/score binding maps the request body
correctly (i.e., ensure each additional_bindings block for these RPCs includes
body: "*").
- Line 7: Update the protobuf go_package option to a full Go module import path
instead of the relative path currently set in the file (the line `option
go_package = "./campusapis/fitness/v1";`); replace it with your module's full
import path plus an optional alias (for example
`github.com/your_org/your_repo/campusapis/fitness/v1;fitnessv1pb`) so
protoc-gen-go can generate importable Go code and keep the format consistent
with other proto files.
In `@campusapis/teaching/v1/courses.go`:
- Around line 3-13: The ToGetScheduleResponse method currently hardcodes
SemesterStartTimestamp using schoolConst.SemesterStartTimestamp which breaks
queries for non-default terms; change the signature of
Courses.ToGetScheduleResponse (the method on type Courses) to accept a
semesterStartTimestamp parameter and set
ScheduleResponseData.SemesterStartTimestamp to that parameter instead of
schoolConst.SemesterStartTimestamp, and update callers to compute/lookup the
correct semester start timestamp based on the GetScheduleRequest (year/term) and
pass it into ToGetScheduleResponse so historical/future term queries return the
correct value.
In `@docs/swagger/campusapis/fitness/v1/fitness.swagger.json`:
- Around line 62-199: The Swagger shows POST/PATCH to /fitness/score being
rendered as query params because the proto RPCs StoreFitnessScore and
UpdateFitnessScore omitted body: "*" in their additional_bindings; update both
RPC options so each additional_bindings block for StoreFitnessScore and
UpdateFitnessScore includes body: "*" (matching the primary binding), then
regenerate the Swagger to ensure /fitness/score endpoints use request body
instead of query parameters.
🧹 Nitpick comments (1)
docs/swagger/campusapis/fitness/v1/fitness.swagger.json (1)
1-18: 请确认是否需要鉴权:Swagger 未声明安全定义当前 Swagger 2.0 未包含
securityDefinitions与全局/operationsecurity。如果接口需要认证,这会导致文档和生成客户端缺失鉴权配置。请确认安全需求并补齐对应定义(如 API key/Bearer)。Also applies to: 448-476
campusapis/fitness/v1/fitness.proto
Outdated
|
|
||
| import "google/api/annotations.proto"; | ||
|
|
||
| option go_package = "./campusapis/fitness/v1"; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find all go_package declarations
rg -n 'option go_package'
# Check module path
if [ -f go.mod ]; then
echo "=== go.mod ==="
head -5 go.mod
fiRepository: hduhelp/api_open_sdk
Length of output: 184
🌐 Web query:
Go modules proto go_package relative path import valid
💡 Result:
Short answer: With Go modules you must use module-aware (fully qualified) Go import paths in proto go_package values or supply equivalent mappings to protoc. Relative import paths (./ or ../) in go_package are not valid in module mode.
Why and options:
- protoc-gen-go expects a Go import path (e.g. example.com/project/protos/foo) in option go_package; generated imports and output placement are computed from that. Using relative paths breaks module-mode imports. [1][2]
- Alternatives:
- Put a full module path in option go_package (recommended). [2]
- Pass M=<import_path> mappings to protoc (or use build tooling that does this). [2]
- Use --go_opt=paths=source_relative (or the newer module= prefix behaviors) to control output placement, but you still must provide import paths for cross-file imports; the module flag can help place generated files under a module prefix. [1][3]
References:
[1] Protobuf Go generated code guide — packages, go_package, paths/module flags.
[2] Discussion / Q&A: relative imports in protobuf + Go modules (StackOverflow + community guidance).
[3] protoc-gen-go / release notes and module/paths behavior.
🌐 Web query:
protobuf go_package option best practices Go modules
💡 Result:
Short best-practices for option go_package when using Go modules
-
Always declare go_package inside the .proto. Use the full Go module import path (module path + package directory) so generated code has a stable import path. Example:
option go_package = "github.com/acme/project/api/proto/v1;apipb". [1][3] -
Include an explicit package name after a semicolon when the directory tail is not the desired Go package identifier:
option go_package = "github.com/acme/project/api/proto/v1;apipb". [1][3] -
Version your proto package paths for breaking changes (v1, v2…) consistent with Go module semantics (so import paths remain unique). [1][5]
-
Prefer a central module that publishes generated Go packages for widely‑shared protos rather than generating copies in many modules. This avoids duplicate protobuf descriptors and runtime global-registry conflicts. If you must generate in-repo, keep generated Go code in an internal/ package or a clearly isolated module. [1][2][5]
-
If you cannot edit upstream .proto files, map proto→Go import paths at generation time with protoc’s M flag (e.g. --go_opt=Mpath/to.proto=github.com/you/module/apipb). Prefer adding go_package upstream when possible. [1][4]
-
Pick unique proto package names (proto package and go package) — avoid generic names to prevent name collisions across repos. Coordinate with proto owners for a canonical go_package if the proto is shared. [1][2]
-
Don’t rely on implicit filesystem layout or GOPATH heuristics; be explicit in the .proto or with --go_opt mappings so builds are reproducible across modules/CI. [1][3]
Sources
- Official protobuf Go generated code guidance. [1]
- protobuf Go FAQ (vendoring, package conflicts). [2]
- Protobuf getting-started/Tutorial (examples of go_package usage). [3]
- StackOverflow discussion on generation with Go modules and go_package mappings. [4]
- Blog/discussion on storing/generated Go bindings and global registry issues. [5]
go_package 相对路径在 Go modules 中无效,需修改为完整 import path
option go_package = "./campusapis/fitness/v1"; 中的相对路径不符合 Go modules 规范。protoc-gen-go 要求 go_package 使用完整的 Go import path(例如 github.com/hduhelp/api_open_sdk/campusapis/fitness/v1),相对路径会导致生成的代码无法正常导入和使用。
建议改为完整 module path + 可选别名的形式,如 module/path/fitness/v1;fitnessv1pb,并与仓库其他 proto 文件保持一致。
🤖 Prompt for AI Agents
In `@campusapis/fitness/v1/fitness.proto` at line 7, Update the protobuf
go_package option to a full Go module import path instead of the relative path
currently set in the file (the line `option go_package =
"./campusapis/fitness/v1";`); replace it with your module's full import path
plus an optional alias (for example
`github.com/your_org/your_repo/campusapis/fitness/v1;fitnessv1pb`) so
protoc-gen-go can generate importable Go code and keep the format consistent
with other proto files.
campusapis/fitness/v1/fitness.proto
Outdated
| rpc StoreFitnessScore(StoreFitnessScoreRequest) returns (StoreFitnessScoreResponse) { | ||
| option (google.api.http) = { | ||
| post: "/fitness/v1/score" | ||
| body: "*" | ||
| additional_bindings { | ||
| post: "/fitness/score" | ||
| } | ||
| }; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "fitness.proto" -type fRepository: hduhelp/api_open_sdk
Length of output: 101
🏁 Script executed:
cat -n ./campusapis/fitness/v1/fitness.protoRepository: hduhelp/api_open_sdk
Length of output: 3889
additional_bindings 缺少 body 导致请求体映射错误
StoreFitnessScore 和 UpdateFitnessScore 的 additional_bindings 均未声明 body: "*",导致 /fitness/score 的 POST/PATCH 请求参数被误解析为查询参数,与 /fitness/v1/score 行为不一致。需在两个 RPC 的 additional_bindings 中显式添加 body: "*":
建议修复
rpc StoreFitnessScore(StoreFitnessScoreRequest) returns (StoreFitnessScoreResponse) {
option (google.api.http) = {
post: "/fitness/v1/score"
body: "*"
additional_bindings {
post: "/fitness/score"
+ body: "*"
}
};
}
rpc UpdateFitnessScore(UpdateFitnessScoreRequest) returns (UpdateFitnessScoreResponse) {
option (google.api.http) = {
patch: "/fitness/v1/score"
body: "*"
additional_bindings {
patch: "/fitness/score"
+ body: "*"
}
};
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| rpc StoreFitnessScore(StoreFitnessScoreRequest) returns (StoreFitnessScoreResponse) { | |
| option (google.api.http) = { | |
| post: "/fitness/v1/score" | |
| body: "*" | |
| additional_bindings { | |
| post: "/fitness/score" | |
| } | |
| }; | |
| rpc StoreFitnessScore(StoreFitnessScoreRequest) returns (StoreFitnessScoreResponse) { | |
| option (google.api.http) = { | |
| post: "/fitness/v1/score" | |
| body: "*" | |
| additional_bindings { | |
| post: "/fitness/score" | |
| body: "*" | |
| } | |
| }; |
🤖 Prompt for AI Agents
In `@campusapis/fitness/v1/fitness.proto` around lines 12 - 19,
additional_bindings for StoreFitnessScore and UpdateFitnessScore omit body
mapping, causing POST/PATCH to /fitness/score to treat the payload as query
params; update the RPC options for both StoreFitnessScore and UpdateFitnessScore
to add body: "*" inside their additional_bindings so the /fitness/score binding
maps the request body correctly (i.e., ensure each additional_bindings block for
these RPCs includes body: "*").
campusapis/fitness/v1/fitness.proto
Outdated
| rpc UpdateFitnessScore(UpdateFitnessScoreRequest) returns (UpdateFitnessScoreResponse) { | ||
| option (google.api.http) = { | ||
| patch: "/fitness/v1/score" | ||
| body: "*" | ||
| additional_bindings { | ||
| patch: "/fitness/score" | ||
| } | ||
| }; | ||
| } |
There was a problem hiding this comment.
PATCH 请求缺少字段 presence,无法安全做部分更新
UpdateFitnessScoreRequest 的字段全为标量且不可区分“未提供”与“零值”,但你们用的是 PATCH。若客户端只传部分字段,将无法避免“误清零”。建议:
- 改为 PUT(要求完整 payload),或
- 引入
google.protobuf.FieldMask+FitnessScore/optional字段来表达更新范围。
Also applies to: 72-91
🤖 Prompt for AI Agents
In `@campusapis/fitness/v1/fitness.proto` around lines 23 - 31, The PATCH RPC
UpdateFitnessScore currently takes scalar fields that can't represent "not
provided" and risks accidental zeroing; fix by either changing rpc
UpdateFitnessScore to use PUT with a full FitnessScore payload, or (preferred)
keep PATCH but modify UpdateFitnessScoreRequest to include a
google.protobuf.FieldMask update_mask plus a single FitnessScore score (or make
scalar fields explicitly optional), update the HTTP annotation accordingly, and
ensure server-side update logic respects update_mask; apply the same
FieldMask/optional approach to the other PATCH RPCs in this proto that suffer
the same issue.
| import ( | ||
| "github.com/hduhelp/api_open_sdk/campusapis/staff" | ||
| "github.com/hduhelp/api_open_sdk/schoolConst" | ||
| ) | ||
|
|
||
| func (x *Courses) ToGetScheduleResponse() *GetScheduleResponse { | ||
| return &GetScheduleResponse{ | ||
| Data: x.GetScheduleResponseCourse(), | ||
| Data: &ScheduleResponseData{ | ||
| Course: x.GetScheduleResponseCourse(), | ||
| SemesterStartTimestamp: schoolConst.SemesterStartTimestamp, | ||
| }, |
There was a problem hiding this comment.
❓ Verification inconclusive
Script executed:
find . -type f -name "courses.go" | grep -E "teaching/v1|campusapis" | head -5Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
./campusapis/teaching/v1/courses.go
Script executed:
git ls-files | grep -E "courses\.go|schoolConst" | head -20Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
campusapis/teaching/v1/courses.go
schoolConst/const.go
Script executed:
find . -type f -name "*.go" | grep -v vendor | head -30Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
./aggregatingapis/infostream/v1/infostream.pb.go
./aggregatingapis/infostream/v1/infostream.pb.gw.go
./aggregatingapis/infostream/v1/infostream_grpc.pb.go
./aggregatingapis/time/v1/time.pb.go
./aggregatingapis/time/v1/time.pb.gw.go
./aggregatingapis/time/v1/time_grpc.pb.go
./aliyun/sls/config.go
./aliyun/sls/sls.go
./api/cache/gocache.go
./api/cache/gocache_test.go
./api/cache/interface.go
./api/grpc_client/client.go
./api/grpc_gateway/grpc_gateway.go
./api/grpc_gateway/mux.go
./api/grpc_server/options.go
./api/grpc_server/server.go
./api/locker/locker.go
./api/locker/options.go
./api/locker/ratelimit.go
./campusapis/backup/backup.pb.go
./campusapis/backup/backup.pb.gw.go
./campusapis/backup/backup_grpc.pb.go
./campusapis/card/v1/card.pb.go
./campusapis/card/v1/card.pb.gw.go
./campusapis/card/v1/card_grpc.pb.go
./campusapis/gate/v1/callback.pb.go
./campusapis/gate/v1/callback.pb.gw.go
./campusapis/gate/v1/callback_grpc.pb.go
./campusapis/gate/v1/defined.go
./campusapis/gate/v1/defined.pb.go
Script executed:
cat -n ./campusapis/teaching/v1/courses.go | head -50Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
1 package teachingv1
2
3 import (
4 "github.com/hduhelp/api_open_sdk/campusapis/staff"
5 "github.com/hduhelp/api_open_sdk/schoolConst"
6 )
7
8 func (x *Courses) ToGetScheduleResponse() *GetScheduleResponse {
9 return &GetScheduleResponse{
10 Data: &ScheduleResponseData{
11 Course: x.GetScheduleResponseCourse(),
12 SemesterStartTimestamp: schoolConst.SemesterStartTimestamp,
13 },
14 }
15 }
16
17 func (x *Courses) GetScheduleResponseCourse() (list []*ScheduleResponseCourse) {
18 list = make([]*ScheduleResponseCourse, 0)
19 for _, v := range x.Items {
20 list = append(list, v.ToScheduleResponseCourse())
21 }
22 return list
23 }
24
25 func (i CourseItems) ToGetScheduleResponse() (list []*ScheduleResponseCourse) {
26 list = make([]*ScheduleResponseCourse, 0)
27 for _, v := range i {
28 list = append(list, v.ToScheduleResponseCourse())
29 }
30 return list
31 }
32
33 func (x *CourseItem) ToScheduleResponseCourse() *ScheduleResponseCourse {
34 return &ScheduleResponseCourse{
35 ClassID: x.ClassID,
36 ClassName: x.ClassName,
37 ClassTime: x.ClassTime,
38 CourseID: x.CourseID,
39 CourseName: x.CourseName,
40 Credit: x.Credit,
41 Schedule: x.GetScheduleResponseCourse_Schedule(),
42 SchoolYear: x.SchoolYear.FullName(),
43 Semester: x.Semester.Num,
44 }
45 }
46
47 func (x *CourseItem) GetScheduleResponseCourse_Schedule() (list []*ScheduleResponseCourse_ScheduleInfo) {
48 list = make([]*ScheduleResponseCourse_ScheduleInfo, 0)
49 if x.Schedule == nil {
50 return list
Script executed:
cat -n ./schoolConst/const.go | head -100Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
1 package schoolConst
2
3 import (
4 "math"
5 "time"
6 )
7
8 const (
9 SchoolYear = 2025
10 Semester = 1
11 SemesterStartTimestamp = int64(1757865600) // 2025-9-15 00:00:00
12 )
13
14 func getWeekNum() int {
15 timeStart := SemesterStartTimestamp
16 return int(math.Floor(float64(time.Now().Unix()-timeStart)/(86400*7))) + 1
17 }
18
19 func getWeekDay() int {
20 day := int(time.Now().Weekday())
21 return day
22 }
23
24 type TimeData struct {
25 SchoolYear int `json:"schoolYear"`
26 Semester int `json:"semester"`
27 SemesterStartTimestamp int64 `json:"semester_start_timestamp"`
28 WeekNow int `json:"weekNow"`
29 WeekDayNow int `json:"weekDayNow"`
30 Timestamp int64 `json:"timeStamp"`
31 Section int `json:"section"`
32 }
33
34 func GetTimeData() *TimeData {
35 timeNow := time.Now()
36 hour := timeNow.Hour()
37 minute := time.Now().Minute() + hour*60
38 tMap := []int{0, 530, 580, 645, 695, 745, 855, 905, 960, 1010, 1155, 1205, 1255}
39 section := -1
40 for i := 0; i < len(tMap); i++ {
41 if minute < tMap[i] {
42 section = i
43 break
44 }
45 }
46
47 timed := &TimeData{
48 SchoolYear: SchoolYear,
49 Semester: Semester,
50 SemesterStartTimestamp: SemesterStartTimestamp,
51 WeekNow: getWeekNum(),
52 WeekDayNow: getWeekDay(),
53 Timestamp: time.Now().Unix(),
54 Section: section,
55 }
56
57 return timed
58 }
Script executed:
rg "GetScheduleRequest" --type go | head -20Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
campusapis/teaching/v1/teaching_grpc.pb.go: GetSchedule(ctx context.Context, in *GetScheduleRequest, opts ...grpc.CallOption) (*GetScheduleResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go:func (c *teachingServiceClient) GetSchedule(ctx context.Context, in *GetScheduleRequest, opts ...grpc.CallOption) (*GetScheduleResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go: GetSchedule(context.Context, *GetScheduleRequest) (*GetScheduleResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go:func (UnimplementedTeachingServiceServer) GetSchedule(context.Context, *GetScheduleRequest) (*GetScheduleResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go: in := new(GetScheduleRequest)
campusapis/teaching/v1/teaching_grpc.pb.go: return srv.(TeachingServiceServer).GetSchedule(ctx, req.(*GetScheduleRequest))
campusapis/teaching/v1/teaching.pb.gw.go: protoReq GetScheduleRequest
campusapis/teaching/v1/teaching.pb.gw.go: protoReq GetScheduleRequest
campusapis/teaching/v1/teaching.pb.gw.go: protoReq GetScheduleRequest
campusapis/teaching/v1/teaching.pb.gw.go: protoReq GetScheduleRequest
campusapis/teaching/v1/teaching.pb.gw.go: protoReq GetScheduleRequest
campusapis/teaching/v1/teaching.pb.gw.go: protoReq GetScheduleRequest
campusapis/teaching/v1/teaching.pb.go:// GetScheduleRequest 根据参数和预设优先级拼装查询日期
campusapis/teaching/v1/teaching.pb.go:type GetScheduleRequest struct {
campusapis/teaching/v1/teaching.pb.go:func (x *GetScheduleRequest) Reset() {
campusapis/teaching/v1/teaching.pb.go: *x = GetScheduleRequest{}
campusapis/teaching/v1/teaching.pb.go:func (x *GetScheduleRequest) String() string {
campusapis/teaching/v1/teaching.pb.go:func (*GetScheduleRequest) ProtoMessage() {}
campusapis/teaching/v1/teaching.pb.go:func (x *GetScheduleRequest) ProtoReflect() protoreflect.Message {
campusapis/teaching/v1/teaching.pb.go:// Deprecated: Use GetScheduleRequest.ProtoReflect.Descriptor instead.
Script executed:
rg "ToGetScheduleResponse" --type go -B 2 -A 2 | head -40Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
campusapis/teaching/v1/courses.go-)
campusapis/teaching/v1/courses.go-
campusapis/teaching/v1/courses.go:func (x *Courses) ToGetScheduleResponse() *GetScheduleResponse {
campusapis/teaching/v1/courses.go- return &GetScheduleResponse{
campusapis/teaching/v1/courses.go- Data: &ScheduleResponseData{
--
campusapis/teaching/v1/courses.go-}
campusapis/teaching/v1/courses.go-
campusapis/teaching/v1/courses.go:func (i CourseItems) ToGetScheduleResponse() (list []*ScheduleResponseCourse) {
campusapis/teaching/v1/courses.go- list = make([]*ScheduleResponseCourse, 0)
campusapis/teaching/v1/courses.go- for _, v := range i {
Script executed:
rg "SchoolYear\|Semester" --type go | grep -E "\.SchoolYear|\.Semester|x\." | head -30Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
Script executed:
rg "type GetScheduleRequest struct" --type go -A 15Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
campusapis/teaching/v1/teaching.pb.go:type GetScheduleRequest struct {
campusapis/teaching/v1/teaching.pb.go- state protoimpl.MessageState `protogen:"open.v1"`
campusapis/teaching/v1/teaching.pb.go- // 学期
campusapis/teaching/v1/teaching.pb.go- Semester string `protobuf:"bytes,1,opt,name=semester,proto3" json:"semester,omitempty"`
campusapis/teaching/v1/teaching.pb.go- // 学年 支持多种格式 如:2019-2020 2019
campusapis/teaching/v1/teaching.pb.go- SchoolYear string `protobuf:"bytes,2,opt,name=schoolYear,proto3" json:"schoolYear,omitempty"`
campusapis/teaching/v1/teaching.pb.go- // 时间戳
campusapis/teaching/v1/teaching.pb.go- Timestamp int32 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
campusapis/teaching/v1/teaching.pb.go- // 周次
campusapis/teaching/v1/teaching.pb.go- Week int32 `protobuf:"varint,4,opt,name=week,proto3" json:"week,omitempty"`
campusapis/teaching/v1/teaching.pb.go- // 星期几
campusapis/teaching/v1/teaching.pb.go- Weekday int32 `protobuf:"varint,5,opt,name=weekday,proto3" json:"weekday,omitempty"`
campusapis/teaching/v1/teaching.pb.go- unknownFields protoimpl.UnknownFields
campusapis/teaching/v1/teaching.pb.go- sizeCache protoimpl.SizeCache
campusapis/teaching/v1/teaching.pb.go-}
campusapis/teaching/v1/teaching.pb.go-
Script executed:
rg "GetSchedule.*Request" --type go -A 10 | head -50Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
campusapis/teaching/v1/teaching_grpc.pb.go: GetSchedule(ctx context.Context, in *GetScheduleRequest, opts ...grpc.CallOption) (*GetScheduleResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 获取学生/教师当前课程表
campusapis/teaching/v1/teaching_grpc.pb.go- GetScheduleNow(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetScheduleNowResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 获取学生/教师当前课程表V2 返回更详细的信息
campusapis/teaching/v1/teaching_grpc.pb.go- GetScheduleNowV2(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetScheduleNowV2Response, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 获取学生/教师当前课程表
campusapis/teaching/v1/teaching_grpc.pb.go- GetScheduleNowV3(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetScheduleNowV3Response, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 获取全局课表,用于推送课程信息,仅内部使用
campusapis/teaching/v1/teaching_grpc.pb.go- GetGlobalSchedule(ctx context.Context, in *GetGlobalScheduleRequest, opts ...grpc.CallOption) (*GetGlobalScheduleResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 通过CLASS_ID获取学生老师列表
campusapis/teaching/v1/teaching_grpc.pb.go- GetClassDetail(ctx context.Context, in *GetClassDetailRequest, opts ...grpc.CallOption) (*GetClassDetailResponse, error)
--
campusapis/teaching/v1/teaching_grpc.pb.go:func (c *teachingServiceClient) GetSchedule(ctx context.Context, in *GetScheduleRequest, opts ...grpc.CallOption) (*GetScheduleResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
campusapis/teaching/v1/teaching_grpc.pb.go- out := new(GetScheduleResponse)
campusapis/teaching/v1/teaching_grpc.pb.go- err := c.cc.Invoke(ctx, TeachingService_GetSchedule_FullMethodName, in, out, cOpts...)
campusapis/teaching/v1/teaching_grpc.pb.go- if err != nil {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, err
campusapis/teaching/v1/teaching_grpc.pb.go- }
campusapis/teaching/v1/teaching_grpc.pb.go- return out, nil
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go-
campusapis/teaching/v1/teaching_grpc.pb.go-func (c *teachingServiceClient) GetScheduleNow(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetScheduleNowResponse, error) {
--
campusapis/teaching/v1/teaching_grpc.pb.go: GetSchedule(context.Context, *GetScheduleRequest) (*GetScheduleResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 获取学生/教师当前课程表
campusapis/teaching/v1/teaching_grpc.pb.go- GetScheduleNow(context.Context, *emptypb.Empty) (*GetScheduleNowResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 获取学生/教师当前课程表V2 返回更详细的信息
campusapis/teaching/v1/teaching_grpc.pb.go- GetScheduleNowV2(context.Context, *emptypb.Empty) (*GetScheduleNowV2Response, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 获取学生/教师当前课程表
campusapis/teaching/v1/teaching_grpc.pb.go- GetScheduleNowV3(context.Context, *emptypb.Empty) (*GetScheduleNowV3Response, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 获取全局课表,用于推送课程信息,仅内部使用
campusapis/teaching/v1/teaching_grpc.pb.go- GetGlobalSchedule(context.Context, *GetGlobalScheduleRequest) (*GetGlobalScheduleResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 通过CLASS_ID获取学生老师列表
campusapis/teaching/v1/teaching_grpc.pb.go- GetClassDetail(context.Context, *GetClassDetailRequest) (*GetClassDetailResponse, error)
--
campusapis/teaching/v1/teaching_grpc.pb.go:func (UnimplementedTeachingServiceServer) GetSchedule(context.Context, *GetScheduleRequest) (*GetScheduleResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetSchedule not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go-func (UnimplementedTeachingServiceServer) GetScheduleNow(context.Context, *emptypb.Empty) (*GetScheduleNowResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetScheduleNow not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go-func (UnimplementedTeachingServiceServer) GetScheduleNowV2(context.Context, *emptypb.Empty) (*GetScheduleNowV2Response, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetScheduleNowV2 not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go-func (UnimplementedTeachingServiceServer) GetScheduleNowV3(context.Context, *emptypb.Empty) (*GetScheduleNowV3Response, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetScheduleNowV3 not implemented")
--
campusapis/teaching/v1/teaching_grpc.pb.go: in := new(GetScheduleRequest)
campusapis/teaching/v1/teaching_grpc.pb.go- if err := dec(in); err != nil {
Script executed:
grep -n "SchoolYear\|Semester" ./campusapis/teaching/v1/teaching.pb.go | head -30Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
38: Semester string `protobuf:"bytes,1,opt,name=semester,proto3" json:"semester,omitempty"`
40: SchoolYear string `protobuf:"bytes,2,opt,name=schoolYear,proto3" json:"schoolYear,omitempty"`
81:func (x *GetScheduleRequest) GetSemester() string {
83: return x.Semester
88:func (x *GetScheduleRequest) GetSchoolYear() string {
90: return x.SchoolYear
179: SemesterStartTimestamp int64 `protobuf:"varint,1,opt,name=semester_start_timestamp,json=semesterStartTimestamp,proto3" json:"semester_start_timestamp,omitempty"`
215:func (x *ScheduleResponseData) GetSemesterStartTimestamp() int64 {
217: return x.SemesterStartTimestamp
247: SchoolYear string `protobuf:"bytes,8,opt,name=SchoolYear,proto3" json:"SchoolYear,omitempty"`
249: Semester int32 `protobuf:"varint,9,opt,name=Semester,proto3" json:"Semester,omitempty"`
333:func (x *ScheduleResponseCourse) GetSchoolYear() string {
335: return x.SchoolYear
340:func (x *ScheduleResponseCourse) GetSemester() int32 {
342: return x.Semester
409: SchoolYear *schoolTime.SchoolYear `protobuf:"bytes,7,opt,name=SchoolYear,proto3" json:"SchoolYear,omitempty"`
411: Semester *schoolTime.Semester `protobuf:"bytes,8,opt,name=Semester,proto3" json:"Semester,omitempty"`
490:func (x *CourseItem) GetSchoolYear() *schoolTime.SchoolYear {
492: return x.SchoolYear
497:func (x *CourseItem) GetSemester() *schoolTime.Semester {
499: return x.Semester
1486: SchoolYear string `protobuf:"bytes,1,opt,name=schoolYear,proto3" json:"schoolYear,omitempty"`
1488: Semester string `protobuf:"bytes,2,opt,name=semester,proto3" json:"semester,omitempty"`
1523:func (x *GetClassroomsRequest) GetSchoolYear() string {
1525: return x.SchoolYear
1530:func (x *GetClassroomsRequest) GetSemester() string {
1532: return x.Semester
1540: Semester string `protobuf:"bytes,1,opt,name=semester,proto3" json:"semester,omitempty"`
1542: SchoolYear string `protobuf:"bytes,2,opt,name=schoolYear,proto3" json:"schoolYear,omitempty"`
1579:func (x *GetClassroomUsagesRequest) GetSemester() string {
Script executed:
rg "\.ToGetScheduleResponse\(\)" --type go -B 3 -A 3 | head -50Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
Script executed:
rg "type ScheduleResponseData" --type go -A 10Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
campusapis/teaching/v1/teaching.pb.go:type ScheduleResponseData struct {
campusapis/teaching/v1/teaching.pb.go- state protoimpl.MessageState `protogen:"open.v1"`
campusapis/teaching/v1/teaching.pb.go- SemesterStartTimestamp int64 `protobuf:"varint,1,opt,name=semester_start_timestamp,json=semesterStartTimestamp,proto3" json:"semester_start_timestamp,omitempty"`
campusapis/teaching/v1/teaching.pb.go- Course []*ScheduleResponseCourse `protobuf:"bytes,2,rep,name=course,proto3" json:"course,omitempty"`
campusapis/teaching/v1/teaching.pb.go- unknownFields protoimpl.UnknownFields
campusapis/teaching/v1/teaching.pb.go- sizeCache protoimpl.SizeCache
campusapis/teaching/v1/teaching.pb.go-}
campusapis/teaching/v1/teaching.pb.go-
campusapis/teaching/v1/teaching.pb.go-func (x *ScheduleResponseData) Reset() {
campusapis/teaching/v1/teaching.pb.go- *x = ScheduleResponseData{}
campusapis/teaching/v1/teaching.pb.go- mi := &file_campusapis_teaching_v1_teaching_proto_msgTypes[2]
Script executed:
rg "type Courses struct" --type go -A 15Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
campusapis/teaching/v1/teaching.pb.go:type Courses struct {
campusapis/teaching/v1/teaching.pb.go- state protoimpl.MessageState `protogen:"open.v1"`
campusapis/teaching/v1/teaching.pb.go- // 课程 map, ClassID -> 课程信息
campusapis/teaching/v1/teaching.pb.go- Items map[string]*CourseItem `protobuf:"bytes,1,rep,name=Items,proto3" json:"Items,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
campusapis/teaching/v1/teaching.pb.go- unknownFields protoimpl.UnknownFields
campusapis/teaching/v1/teaching.pb.go- sizeCache protoimpl.SizeCache
campusapis/teaching/v1/teaching.pb.go-}
campusapis/teaching/v1/teaching.pb.go-
campusapis/teaching/v1/teaching.pb.go-func (x *Courses) Reset() {
campusapis/teaching/v1/teaching.pb.go- *x = Courses{}
campusapis/teaching/v1/teaching.pb.go- mi := &file_campusapis_teaching_v1_teaching_proto_msgTypes[4]
campusapis/teaching/v1/teaching.pb.go- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
campusapis/teaching/v1/teaching.pb.go- ms.StoreMessageInfo(mi)
campusapis/teaching/v1/teaching.pb.go-}
campusapis/teaching/v1/teaching.pb.go-
campusapis/teaching/v1/teaching.pb.go-func (x *Courses) String() string {
Script executed:
rg "GetScheduleRequest" --type go -A 15 | grep -E "Semester|SchoolYear|Week" | head -20Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
campusapis/teaching/v1/teaching.pb.go- Semester string `protobuf:"bytes,1,opt,name=semester,proto3" json:"semester,omitempty"`
campusapis/teaching/v1/teaching.pb.go- SchoolYear string `protobuf:"bytes,2,opt,name=schoolYear,proto3" json:"schoolYear,omitempty"`
campusapis/teaching/v1/teaching.pb.go- Week int32 `protobuf:"varint,4,opt,name=week,proto3" json:"week,omitempty"`
campusapis/teaching/v1/teaching.pb.go- Weekday int32 `protobuf:"varint,5,opt,name=weekday,proto3" json:"weekday,omitempty"`
campusapis/teaching/v1/teaching.pb.go:func (x *GetScheduleRequest) GetSemester() string {
campusapis/teaching/v1/teaching.pb.go- return x.Semester
campusapis/teaching/v1/teaching.pb.go:func (x *GetScheduleRequest) GetSchoolYear() string {
campusapis/teaching/v1/teaching.pb.go- return x.SchoolYear
campusapis/teaching/v1/teaching.pb.go:func (x *GetScheduleRequest) GetWeek() int32 {
campusapis/teaching/v1/teaching.pb.go- return x.Week
campusapis/teaching/v1/teaching.pb.go:func (x *GetScheduleRequest) GetWeekday() int32 {
campusapis/teaching/v1/teaching.pb.go- return x.Weekday
Script executed:
cat -n ./campusapis/teaching/v1/teaching.pb.go | sed -n '30,50p'Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
30 // 优先级:
31 // 1. 若含 时间戳: 根据时间戳查询,并标记时间戳所在周(研究生暂未支持)
32 // 2. 若含 学年、学期、周次:返回整个学期课表,并标记指定周(研究生暂未支持)
33 // 3. 若含 学年、学期: 返回整个学期课表
34 // 都不命中:返回当前时间所在周的课表,并标记当前周(研究生暂未支持)
35 type GetScheduleRequest struct {
36 state protoimpl.MessageState `protogen:"open.v1"`
37 // 学期
38 Semester string `protobuf:"bytes,1,opt,name=semester,proto3" json:"semester,omitempty"`
39 // 学年 支持多种格式 如:2019-2020 2019
40 SchoolYear string `protobuf:"bytes,2,opt,name=schoolYear,proto3" json:"schoolYear,omitempty"`
41 // 时间戳
42 Timestamp int32 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
43 // 周次
44 Week int32 `protobuf:"varint,4,opt,name=week,proto3" json:"week,omitempty"`
45 // 星期几
46 Weekday int32 `protobuf:"varint,5,opt,name=weekday,proto3" json:"weekday,omitempty"`
47 unknownFields protoimpl.UnknownFields
48 sizeCache protoimpl.SizeCache
49 }
50
Script executed:
rg "func.*GetSchedule\(" --type go -B 2 -A 20 | head -100Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go-
campusapis/teaching/v1/teaching_grpc.pb.go:func (c *teachingServiceClient) GetSchedule(ctx context.Context, in *GetScheduleRequest, opts ...grpc.CallOption) (*GetScheduleResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
campusapis/teaching/v1/teaching_grpc.pb.go- out := new(GetScheduleResponse)
campusapis/teaching/v1/teaching_grpc.pb.go- err := c.cc.Invoke(ctx, TeachingService_GetSchedule_FullMethodName, in, out, cOpts...)
campusapis/teaching/v1/teaching_grpc.pb.go- if err != nil {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, err
campusapis/teaching/v1/teaching_grpc.pb.go- }
campusapis/teaching/v1/teaching_grpc.pb.go- return out, nil
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go-
campusapis/teaching/v1/teaching_grpc.pb.go-func (c *teachingServiceClient) GetScheduleNow(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetScheduleNowResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
campusapis/teaching/v1/teaching_grpc.pb.go- out := new(GetScheduleNowResponse)
campusapis/teaching/v1/teaching_grpc.pb.go- err := c.cc.Invoke(ctx, TeachingService_GetScheduleNow_FullMethodName, in, out, cOpts...)
campusapis/teaching/v1/teaching_grpc.pb.go- if err != nil {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, err
campusapis/teaching/v1/teaching_grpc.pb.go- }
campusapis/teaching/v1/teaching_grpc.pb.go- return out, nil
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go-
campusapis/teaching/v1/teaching_grpc.pb.go-func (c *teachingServiceClient) GetScheduleNowV2(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetScheduleNowV2Response, error) {
--
campusapis/teaching/v1/teaching_grpc.pb.go-type UnimplementedTeachingServiceServer struct{}
campusapis/teaching/v1/teaching_grpc.pb.go-
campusapis/teaching/v1/teaching_grpc.pb.go:func (UnimplementedTeachingServiceServer) GetSchedule(context.Context, *GetScheduleRequest) (*GetScheduleResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetSchedule not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go-func (UnimplementedTeachingServiceServer) GetScheduleNow(context.Context, *emptypb.Empty) (*GetScheduleNowResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetScheduleNow not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go-func (UnimplementedTeachingServiceServer) GetScheduleNowV2(context.Context, *emptypb.Empty) (*GetScheduleNowV2Response, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetScheduleNowV2 not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go-func (UnimplementedTeachingServiceServer) GetScheduleNowV3(context.Context, *emptypb.Empty) (*GetScheduleNowV3Response, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetScheduleNowV3 not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go-func (UnimplementedTeachingServiceServer) GetGlobalSchedule(context.Context, *GetGlobalScheduleRequest) (*GetGlobalScheduleResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetGlobalSchedule not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go-func (UnimplementedTeachingServiceServer) GetClassDetail(context.Context, *GetClassDetailRequest) (*GetClassDetailResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetClassDetail not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go-func (UnimplementedTeachingServiceServer) GetClassrooms(context.Context, *GetClassroomsRequest) (*GetClassroomsResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetClassrooms not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go-}
--
campusapis/teaching/v1/teaching.pb.go-}
campusapis/teaching/v1/teaching.pb.go-
campusapis/teaching/v1/teaching.pb.go:func (x *ScheduleResponseCourse) GetSchedule() []*ScheduleResponseCourse_ScheduleInfo {
campusapis/teaching/v1/teaching.pb.go- if x != nil {
campusapis/teaching/v1/teaching.pb.go- return x.Schedule
campusapis/teaching/v1/teaching.pb.go- }
campusapis/teaching/v1/teaching.pb.go- return nil
campusapis/teaching/v1/teaching.pb.go-}
campusapis/teaching/v1/teaching.pb.go-
campusapis/teaching/v1/teaching.pb.go-func (x *ScheduleResponseCourse) GetSchoolYear() string {
campusapis/teaching/v1/teaching.pb.go- if x != nil {
campusapis/teaching/v1/teaching.pb.go- return x.SchoolYear
campusapis/teaching/v1/teaching.pb.go- }
campusapis/teaching/v1/teaching.pb.go- return ""
campusapis/teaching/v1/teaching.pb.go-}
campusapis/teaching/v1/teaching.pb.go-
campusapis/teaching/v1/teaching.pb.go-func (x *ScheduleResponseCourse) GetSemester() int32 {
campusapis/teaching/v1/teaching.pb.go- if x != nil {
campusapis/teaching/v1/teaching.pb.go- return x.Semester
campusapis/teaching/v1/teaching.pb.go- }
campusapis/teaching/v1/teaching.pb.go- return 0
campusapis/teaching/v1/teaching.pb.go-}
campusapis/teaching/v1/teaching.pb.go-
--
campusapis/teaching/v1/teaching.pb.go-}
campusapis/teaching/v1/teaching.pb.go-
campusapis/teaching/v1/teaching.pb.go:func (x *CourseItem) GetSchedule() *Schedule {
campusapis/teaching/v1/teaching.pb.go- if x != nil {
campusapis/teaching/v1/teaching.pb.go- return x.Schedule
campusapis/teaching/v1/teaching.pb.go- }
campusapis/teaching/v1/teaching.pb.go- return nil
campusapis/teaching/v1/teaching.pb.go-}
campusapis/teaching/v1/teaching.pb.go-
campusapis/teaching/v1/teaching.pb.go-// 排课列表详情
campusapis/teaching/v1/teaching.pb.go-type Schedule struct {
campusapis/teaching/v1/teaching.pb.go- state protoimpl.MessageState `protogen:"open.v1"`
campusapis/teaching/v1/teaching.pb.go- // 排课 map, 排课ID -> 排课信息
campusapis/teaching/v1/teaching.pb.go- Items map[string]*ScheduleItem `protobuf:"bytes,1,rep,name=Items,proto3" json:"Items,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
campusapis/teaching/v1/teaching.pb.go- unknownFields protoimpl.UnknownFields
campusapis/teaching/v1/teaching.pb.go- sizeCache protoimpl.SizeCache
campusapis/teaching/v1/teaching.pb.go-}
campusapis/teaching/v1/teaching.pb.go-
campusapis/teaching/v1/teaching.pb.go-func (x *Schedule) Reset() {
campusapis/teaching/v1/teaching.pb.go- *x = Schedule{}
campusapis/teaching/v1/teaching.pb.go- mi := &file_campusapis_teaching_v1_teaching_proto_msgTypes[6]
campusapis/teaching/v1/teaching.pb.go- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
campusapis/teaching/v1/teaching.pb.go- ms.StoreMessageInfo(mi)
--
aggregatingapis/infostream/v1/infostream.pb.go-}
aggregatingapis/infostream/v1/infostream.pb.go-
aggregatingapis/infostream/v1/infostream.pb.go:func (x *InfoStreamData) GetSchedule() *ScheduleResp {
aggregatingapis/infostream/v1/infostream.pb.go- if x != nil {
Script executed:
rg "type CourseItem struct" --type go -A 20Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
campusapis/teaching/v1/teaching.pb.go:type CourseItem struct {
campusapis/teaching/v1/teaching.pb.go- state protoimpl.MessageState `protogen:"open.v1"`
campusapis/teaching/v1/teaching.pb.go- // 课程内部ID
campusapis/teaching/v1/teaching.pb.go- ClassID string `protobuf:"bytes,1,opt,name=ClassID,proto3" json:"ClassID,omitempty"`
campusapis/teaching/v1/teaching.pb.go- // 选课号
campusapis/teaching/v1/teaching.pb.go- ClassName string `protobuf:"bytes,2,opt,name=ClassName,proto3" json:"ClassName,omitempty"`
campusapis/teaching/v1/teaching.pb.go- // 课程代码
campusapis/teaching/v1/teaching.pb.go- CourseID string `protobuf:"bytes,3,opt,name=CourseID,proto3" json:"CourseID,omitempty"`
campusapis/teaching/v1/teaching.pb.go- // 课程中文名
campusapis/teaching/v1/teaching.pb.go- CourseName string `protobuf:"bytes,4,opt,name=CourseName,proto3" json:"CourseName,omitempty"`
campusapis/teaching/v1/teaching.pb.go- // 上课时间中文,如: 星期一第6-7节{1-2周};星期一第6-7节{3-17周}
campusapis/teaching/v1/teaching.pb.go- ClassTime string `protobuf:"bytes,5,opt,name=ClassTime,proto3" json:"ClassTime,omitempty"`
campusapis/teaching/v1/teaching.pb.go- // 学分
campusapis/teaching/v1/teaching.pb.go- Credit string `protobuf:"bytes,6,opt,name=Credit,proto3" json:"Credit,omitempty"`
campusapis/teaching/v1/teaching.pb.go- // 学年
campusapis/teaching/v1/teaching.pb.go- SchoolYear *schoolTime.SchoolYear `protobuf:"bytes,7,opt,name=SchoolYear,proto3" json:"SchoolYear,omitempty"`
campusapis/teaching/v1/teaching.pb.go- // 学期
campusapis/teaching/v1/teaching.pb.go- Semester *schoolTime.Semester `protobuf:"bytes,8,opt,name=Semester,proto3" json:"Semester,omitempty"`
campusapis/teaching/v1/teaching.pb.go- // 排课详情
campusapis/teaching/v1/teaching.pb.go- Schedule *Schedule `protobuf:"bytes,9,opt,name=Schedule,proto3" json:"Schedule,omitempty"`
campusapis/teaching/v1/teaching.pb.go- unknownFields protoimpl.UnknownFields
Script executed:
rg "type SchoolYear" --type go -B 2 -A 10 | head -50Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
campusapis/schoolTime/defined.pb.go-
campusapis/schoolTime/defined.pb.go-// 学年
campusapis/schoolTime/defined.pb.go:type SchoolYear struct {
campusapis/schoolTime/defined.pb.go- state protoimpl.MessageState `protogen:"open.v1"`
campusapis/schoolTime/defined.pb.go- // 学年开始年,如:2021-2022 学年为 2021
campusapis/schoolTime/defined.pb.go- Year int32 `protobuf:"varint,1,opt,name=Year,proto3" json:"Year,omitempty"`
campusapis/schoolTime/defined.pb.go- unknownFields protoimpl.UnknownFields
campusapis/schoolTime/defined.pb.go- sizeCache protoimpl.SizeCache
campusapis/schoolTime/defined.pb.go-}
campusapis/schoolTime/defined.pb.go-
campusapis/schoolTime/defined.pb.go-func (x *SchoolYear) Reset() {
campusapis/schoolTime/defined.pb.go- *x = SchoolYear{}
campusapis/schoolTime/defined.pb.go- mi := &file_campusapis_schoolTime_defined_proto_msgTypes[1]
Script executed:
rg "ToGetScheduleResponse\(" --type go -B 5 -A 2Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
campusapis/teaching/v1/courses.go-import (
campusapis/teaching/v1/courses.go- "github.com/hduhelp/api_open_sdk/campusapis/staff"
campusapis/teaching/v1/courses.go- "github.com/hduhelp/api_open_sdk/schoolConst"
campusapis/teaching/v1/courses.go-)
campusapis/teaching/v1/courses.go-
campusapis/teaching/v1/courses.go:func (x *Courses) ToGetScheduleResponse() *GetScheduleResponse {
campusapis/teaching/v1/courses.go- return &GetScheduleResponse{
campusapis/teaching/v1/courses.go- Data: &ScheduleResponseData{
--
campusapis/teaching/v1/courses.go- list = append(list, v.ToScheduleResponseCourse())
campusapis/teaching/v1/courses.go- }
campusapis/teaching/v1/courses.go- return list
campusapis/teaching/v1/courses.go-}
campusapis/teaching/v1/courses.go-
campusapis/teaching/v1/courses.go:func (i CourseItems) ToGetScheduleResponse() (list []*ScheduleResponseCourse) {
campusapis/teaching/v1/courses.go- list = make([]*ScheduleResponseCourse, 0)
campusapis/teaching/v1/courses.go- for _, v := range i {
Script executed:
rg "type Semester struct" --type go -A 10 | head -30Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
campusapis/schoolTime/defined.pb.go:type Semester struct {
campusapis/schoolTime/defined.pb.go- state protoimpl.MessageState `protogen:"open.v1"`
campusapis/schoolTime/defined.pb.go- Num int32 `protobuf:"varint,1,opt,name=Num,proto3" json:"Num,omitempty"`
campusapis/schoolTime/defined.pb.go- unknownFields protoimpl.UnknownFields
campusapis/schoolTime/defined.pb.go- sizeCache protoimpl.SizeCache
campusapis/schoolTime/defined.pb.go-}
campusapis/schoolTime/defined.pb.go-
campusapis/schoolTime/defined.pb.go-func (x *Semester) Reset() {
campusapis/schoolTime/defined.pb.go- *x = Semester{}
campusapis/schoolTime/defined.pb.go- mi := &file_campusapis_schoolTime_defined_proto_msgTypes[2]
campusapis/schoolTime/defined.pb.go- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
Script executed:
rg "SemesterStartTimestamp" --type go | head -20Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
schoolConst/const.go: SemesterStartTimestamp = int64(1757865600) // 2025-9-15 00:00:00
schoolConst/const.go: timeStart := SemesterStartTimestamp
schoolConst/const.go: SemesterStartTimestamp int64 `json:"semester_start_timestamp"`
schoolConst/const.go: SemesterStartTimestamp: SemesterStartTimestamp,
gatewayapis/auth/v1/auth.pb.go: SemesterStartTimestamp int32 `protobuf:"varint,3,opt,name=semester_start_timestamp,json=semesterStartTimestamp,proto3" json:"semester_start_timestamp,omitempty"`
gatewayapis/auth/v1/auth.pb.go:func (x *SchoolTime) GetSemesterStartTimestamp() int32 {
gatewayapis/auth/v1/auth.pb.go: return x.SemesterStartTimestamp
campusapis/teaching/v1/courses.go: SemesterStartTimestamp: schoolConst.SemesterStartTimestamp,
campusapis/teaching/v1/teaching.pb.go: SemesterStartTimestamp int64 `protobuf:"varint,1,opt,name=semester_start_timestamp,json=semesterStartTimestamp,proto3" json:"semester_start_timestamp,omitempty"`
campusapis/teaching/v1/teaching.pb.go:func (x *ScheduleResponseData) GetSemesterStartTimestamp() int64 {
campusapis/teaching/v1/teaching.pb.go: return x.SemesterStartTimestamp
campusapis/teaching/v1/scheduleProcess.go:const timeStart = schoolConst.SemesterStartTimestamp
aggregatingapis/time/v1/time.pb.go: SemesterStartTimestamp int64 `protobuf:"varint,3,opt,name=semesterStartTimestamp,proto3" json:"semesterStartTimestamp,omitempty"`
aggregatingapis/time/v1/time.pb.go:func (x *TimeData) GetSemesterStartTimestamp() int64 {
aggregatingapis/time/v1/time.pb.go: return x.SemesterStartTimestamp
Script executed:
find . -type f -name "*.proto" | xargs grep -l "GetScheduleRequest\|GetScheduleResponse" 2>/dev/null | head -5Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
./campusapis/teaching/v1/teaching.proto
Script executed:
cat -n ./campusapis/teaching/v1/teaching.proto | grep -A 10 -B 10 "SemesterStartTimestamp\|GetScheduleRequest\|GetScheduleResponse" | head -80Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
24 url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt";
25 };
26 };
27 schemes: HTTPS;
28 consumes: "application/json";
29 produces: "application/json";
30 };
31
32 service TeachingService {
33 // 获取学生/教师课程表
34 rpc GetSchedule(GetScheduleRequest) returns (GetScheduleResponse) {
35 option (google.api.http) = {
36 get: "/teaching/v1/schedule"
37 additional_bindings {
38 get: "/teaching/schedule"
39 }
40 additional_bindings {
41 get: "/student/v2/schedule"
42 }
43 };
44 }
--
174 get: "/teaching/v1/class/query/fav/rank"
175 additional_bindings {
176 get: "/teaching/class/query/fav/rank"
177 }
178 };
179 }
180 }
181
182
183
184 // GetScheduleRequest 根据参数和预设优先级拼装查询日期
185 // 优先级:
186 // 1. 若含 时间戳: 根据时间戳查询,并标记时间戳所在周(研究生暂未支持)
187 // 2. 若含 学年、学期、周次:返回整个学期课表,并标记指定周(研究生暂未支持)
188 // 3. 若含 学年、学期: 返回整个学期课表
189 // 都不命中:返回当前时间所在周的课表,并标记当前周(研究生暂未支持)
190 message GetScheduleRequest {
191 //学期
192 string semester = 1;
193 //学年 支持多种格式 如:2019-2020 2019
194 string schoolYear = 2;
195 //时间戳
196 int32 timestamp = 3;
197 //周次
198 int32 week = 4;
199 //星期几
200 int32 weekday = 5;
201 }
202
203 // GetScheduleResponse 课表列表返回体
204 message GetScheduleResponse {
205 int32 error = 1;
206 string msg = 2;
207 ScheduleResponseData data = 3;
208 }
209
210 message ScheduleResponseData {
211 int64 semester_start_timestamp = 1;
212 repeated ScheduleResponseCourse course = 2;
213 }
214
Script executed:
rg "func.*GetSchedule" --type go -B 5 | grep -E "func|GetSchedule|Request|server" | head -40Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
campusapis/teaching/v1/courses.go:func (x *Courses) ToGetScheduleResponse() *GetScheduleResponse {
campusapis/teaching/v1/courses.go:func (x *Courses) GetScheduleResponseCourse() (list []*ScheduleResponseCourse) {
campusapis/teaching/v1/courses.go:func (i CourseItems) ToGetScheduleResponse() (list []*ScheduleResponseCourse) {
campusapis/teaching/v1/courses.go:func (x *CourseItem) GetScheduleResponseCourse_Schedule() (list []*ScheduleResponseCourse_ScheduleInfo) {
campusapis/teaching/v1/teaching_grpc.pb.go-func NewTeachingServiceClient(cc grpc.ClientConnInterface) TeachingServiceClient {
campusapis/teaching/v1/teaching_grpc.pb.go:func (c *teachingServiceClient) GetSchedule(ctx context.Context, in *GetScheduleRequest, opts ...grpc.CallOption) (*GetScheduleResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go:func (c *teachingServiceClient) GetScheduleNow(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetScheduleNowResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go:func (c *teachingServiceClient) GetScheduleNowV2(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetScheduleNowV2Response, error) {
campusapis/teaching/v1/teaching_grpc.pb.go:func (c *teachingServiceClient) GetScheduleNowV3(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetScheduleNowV3Response, error) {
campusapis/teaching/v1/teaching_grpc.pb.go:func (UnimplementedTeachingServiceServer) GetSchedule(context.Context, *GetScheduleRequest) (*GetScheduleResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetSchedule not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go:func (UnimplementedTeachingServiceServer) GetScheduleNow(context.Context, *emptypb.Empty) (*GetScheduleNowResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetScheduleNow not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go:func (UnimplementedTeachingServiceServer) GetScheduleNowV2(context.Context, *emptypb.Empty) (*GetScheduleNowV2Response, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetScheduleNowV2 not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go:func (UnimplementedTeachingServiceServer) GetScheduleNowV3(context.Context, *emptypb.Empty) (*GetScheduleNowV3Response, error) {
campusapis/teaching/v1/teaching_grpc.pb.go:func _TeachingService_GetSchedule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return srv.(TeachingServiceServer).GetSchedule(ctx, req.(*GetScheduleRequest))
campusapis/teaching/v1/teaching_grpc.pb.go:func _TeachingService_GetScheduleNow_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return srv.(TeachingServiceServer).GetScheduleNow(ctx, req.(*emptypb.Empty))
campusapis/teaching/v1/teaching_grpc.pb.go:func _TeachingService_GetScheduleNowV2_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return srv.(TeachingServiceServer).GetScheduleNowV2(ctx, req.(*emptypb.Empty))
campusapis/teaching/v1/teaching_grpc.pb.go:func _TeachingService_GetScheduleNowV3_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
campusapis/teaching/v1/teaching.pb.go:func (x *GetScheduleRequest) Reset() {
campusapis/teaching/v1/teaching.pb.go:func (x *GetScheduleRequest) String() string {
campusapis/teaching/v1/teaching.pb.go:func (*GetScheduleRequest) ProtoMessage() {}
campusapis/teaching/v1/teaching.pb.go:func (x *GetScheduleRequest) ProtoReflect() protoreflect.Message {
campusapis/teaching/v1/teaching.pb.go-// Deprecated: Use GetScheduleRequest.ProtoReflect.Descriptor instead.
campusapis/teaching/v1/teaching.pb.go:func (*GetScheduleRequest) Descriptor() ([]byte, []int) {
campusapis/teaching/v1/teaching.pb.go:func (x *GetScheduleRequest) GetSemester() string {
campusapis/teaching/v1/teaching.pb.go:func (x *GetScheduleRequest) GetSchoolYear() string {
campusapis/teaching/v1/teaching.pb.go:func (x *GetScheduleRequest) GetTimestamp() int32 {
campusapis/teaching/v1/teaching.pb.go:func (x *GetScheduleRequest) GetWeek() int32 {
campusapis/teaching/v1/teaching.pb.go:func (x *GetScheduleRequest) GetWeekday() int32 {
campusapis/teaching/v1/teaching.pb.go:func (x *GetScheduleResponse) Reset() {
campusapis/teaching/v1/teaching.pb.go:func (x *GetScheduleResponse) String() string {
campusapis/teaching/v1/teaching.pb.go:func (*GetScheduleResponse) ProtoMessage() {}
campusapis/teaching/v1/teaching.pb.go:func (x *GetScheduleResponse) ProtoReflect() protoreflect.Message {
campusapis/teaching/v1/teaching.pb.go-// Deprecated: Use GetScheduleResponse.ProtoReflect.Descriptor instead.
campusapis/teaching/v1/teaching.pb.go:func (*GetScheduleResponse) Descriptor() ([]byte, []int) {
Script executed:
find . -type f -name "*.go" -path "*/teaching/*" | xargs grep -l "GetScheduleRequest" | grep -v "pb.go" | grep -v "test"Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
./campusapis/teaching/v1/teaching.pb.gw.go
Script executed:
rg "TeachingServiceServer" --type go -A 30 | grep -A 30 "GetSchedule.*Request" | head -60Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
campusapis/teaching/v1/teaching_grpc.pb.go- GetSchedule(context.Context, *GetScheduleRequest) (*GetScheduleResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 获取学生/教师当前课程表
campusapis/teaching/v1/teaching_grpc.pb.go- GetScheduleNow(context.Context, *emptypb.Empty) (*GetScheduleNowResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 获取学生/教师当前课程表V2 返回更详细的信息
campusapis/teaching/v1/teaching_grpc.pb.go- GetScheduleNowV2(context.Context, *emptypb.Empty) (*GetScheduleNowV2Response, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 获取学生/教师当前课程表
campusapis/teaching/v1/teaching_grpc.pb.go- GetScheduleNowV3(context.Context, *emptypb.Empty) (*GetScheduleNowV3Response, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 获取全局课表,用于推送课程信息,仅内部使用
campusapis/teaching/v1/teaching_grpc.pb.go- GetGlobalSchedule(context.Context, *GetGlobalScheduleRequest) (*GetGlobalScheduleResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 通过CLASS_ID获取学生老师列表
campusapis/teaching/v1/teaching_grpc.pb.go- GetClassDetail(context.Context, *GetClassDetailRequest) (*GetClassDetailResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 获取所有教室列表
campusapis/teaching/v1/teaching_grpc.pb.go- GetClassrooms(context.Context, *GetClassroomsRequest) (*GetClassroomsResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 获取某一教室的使用情况
campusapis/teaching/v1/teaching_grpc.pb.go- GetClassroomUsages(context.Context, *GetClassroomUsagesRequest) (*GetClassroomUsagesResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 获取所有空教室列表
campusapis/teaching/v1/teaching_grpc.pb.go- GetUnusedClassrooms(context.Context, *GetUnusedClassroomsRequest) (*GetUnusedClassroomsResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 课程查询
campusapis/teaching/v1/teaching_grpc.pb.go- ClassQuerySearch(context.Context, *ClassQuerySearchRequest) (*ClassQuerySearchResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // magic字段映射表
campusapis/teaching/v1/teaching_grpc.pb.go- ClassQueryMap(context.Context, *emptypb.Empty) (*ClassQueryMapResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 设置课程收藏
campusapis/teaching/v1/teaching_grpc.pb.go- ClassQueryFavSet(context.Context, *ClassQueryFavSetRequest) (*ClassQueryFavSetResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 获取课程收藏
campusapis/teaching/v1/teaching_grpc.pb.go- ClassQueryFavGet(context.Context, *emptypb.Empty) (*ClassQueryFavGetResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 按classIDs获取课程信息
campusapis/teaching/v1/teaching_grpc.pb.go- ClassQueryGet(context.Context, *ClassQueryGetRequest) (*ClassQueryGetResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go- // 获取收藏排行
campusapis/teaching/v1/teaching_grpc.pb.go- ClassQueryFavRank(context.Context, *emptypb.Empty) (*ClassQueryFavRankResponse, error)
campusapis/teaching/v1/teaching_grpc.pb.go: mustEmbedUnimplementedTeachingServiceServer()
campusapis/teaching/v1/teaching_grpc.pb.go-}
--
campusapis/teaching/v1/teaching_grpc.pb.go:func (UnimplementedTeachingServiceServer) GetSchedule(context.Context, *GetScheduleRequest) (*GetScheduleResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetSchedule not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go:func (UnimplementedTeachingServiceServer) GetScheduleNow(context.Context, *emptypb.Empty) (*GetScheduleNowResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetScheduleNow not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go:func (UnimplementedTeachingServiceServer) GetScheduleNowV2(context.Context, *emptypb.Empty) (*GetScheduleNowV2Response, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetScheduleNowV2 not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go:func (UnimplementedTeachingServiceServer) GetScheduleNowV3(context.Context, *emptypb.Empty) (*GetScheduleNowV3Response, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetScheduleNowV3 not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go:func (UnimplementedTeachingServiceServer) GetGlobalSchedule(context.Context, *GetGlobalScheduleRequest) (*GetGlobalScheduleResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetGlobalSchedule not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go:func (UnimplementedTeachingServiceServer) GetClassDetail(context.Context, *GetClassDetailRequest) (*GetClassDetailResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetClassDetail not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go:func (UnimplementedTeachingServiceServer) GetClassrooms(context.Context, *GetClassroomsRequest) (*GetClassroomsResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetClassrooms not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go:func (UnimplementedTeachingServiceServer) GetClassroomUsages(context.Context, *GetClassroomUsagesRequest) (*GetClassroomUsagesResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetClassroomUsages not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go:func (UnimplementedTeachingServiceServer) GetUnusedClassrooms(context.Context, *GetUnusedClassroomsRequest) (*GetUnusedClassroomsResponse, error) {
campusapis/teaching/v1/teaching_grpc.pb.go- return nil, status.Errorf(codes.Unimplemented, "method GetUnusedClassrooms not implemented")
campusapis/teaching/v1/teaching_grpc.pb.go-}
campusapis/teaching/v1/teaching_grpc.pb.go:func (UnimplementedTeachingServiceServer) ClassQuerySearch(context.Context, *ClassQuerySearchRequest) (*ClassQuerySearchResponse, error) {
Script executed:
grep -n "ToGetScheduleResponse\|\.GetSchedule\|TeachingServiceServer" ./campusapis/teaching/v1/teaching.pb.gw.go | head -30Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
52: msg, err := client.GetSchedule(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
56:func local_request_TeachingService_GetSchedule_0(ctx context.Context, marshaler runtime.Marshaler, server TeachingServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
67: msg, err := server.GetSchedule(ctx, &protoReq)
84: msg, err := client.GetSchedule(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
88:func local_request_TeachingService_GetSchedule_1(ctx context.Context, marshaler runtime.Marshaler, server TeachingServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
99: msg, err := server.GetSchedule(ctx, &protoReq)
116: msg, err := client.GetSchedule(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
120:func local_request_TeachingService_GetSchedule_2(ctx context.Context, marshaler runtime.Marshaler, server TeachingServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
131: msg, err := server.GetSchedule(ctx, &protoReq)
140: msg, err := client.GetScheduleNow(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
144:func local_request_TeachingService_GetScheduleNow_0(ctx context.Context, marshaler runtime.Marshaler, server TeachingServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
149: msg, err := server.GetScheduleNow(ctx, &protoReq)
158: msg, err := client.GetScheduleNow(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
162:func local_request_TeachingService_GetScheduleNow_1(ctx context.Context, marshaler runtime.Marshaler, server TeachingServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
167: msg, err := server.GetScheduleNow(ctx, &protoReq)
176: msg, err := client.GetScheduleNowV2(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
180:func local_request_TeachingService_GetScheduleNowV2_0(ctx context.Context, marshaler runtime.Marshaler, server TeachingServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
185: msg, err := server.GetScheduleNowV2(ctx, &protoReq)
194: msg, err := client.GetScheduleNowV2(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
198:func local_request_TeachingService_GetScheduleNowV2_1(ctx context.Context, marshaler runtime.Marshaler, server TeachingServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
203: msg, err := server.GetScheduleNowV2(ctx, &protoReq)
212: msg, err := client.GetScheduleNowV3(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
216:func local_request_TeachingService_GetScheduleNowV3_0(ctx context.Context, marshaler runtime.Marshaler, server TeachingServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
221: msg, err := server.GetScheduleNowV3(ctx, &protoReq)
242:func local_request_TeachingService_GetGlobalSchedule_0(ctx context.Context, marshaler runtime.Marshaler, server TeachingServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
274:func local_request_TeachingService_GetClassDetail_0(ctx context.Context, marshaler runtime.Marshaler, server TeachingServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
306:func local_request_TeachingService_GetClassDetail_1(ctx context.Context, marshaler runtime.Marshaler, server TeachingServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
338:func local_request_TeachingService_GetClassrooms_0(ctx context.Context, marshaler runtime.Marshaler, server TeachingServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
370:func local_request_TeachingService_GetClassrooms_1(ctx context.Context, marshaler runtime.Marshaler, server TeachingServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
402:func local_request_TeachingService_GetClassroomUsages_0(ctx context.Context, marshaler runtime.Marshaler, server TeachingServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
Script executed:
find . -type f -name "*.go" -path "*/teaching/*" ! -name "*pb.go" ! -name "*test*" -exec grep -l "GetScheduleRequest\|GetScheduleResponse" {} \;Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
./campusapis/teaching/v1/teaching.pb.gw.go
./campusapis/teaching/v1/courses.go
Script executed:
cat -n ./campusapis/teaching/v1/teaching.pb.gw.go | sed -n '52,75p'Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
52 msg, err := client.GetSchedule(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
53 return msg, metadata, err
54 }
55
56 func local_request_TeachingService_GetSchedule_0(ctx context.Context, marshaler runtime.Marshaler, server TeachingServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
57 var (
58 protoReq GetScheduleRequest
59 metadata runtime.ServerMetadata
60 )
61 if err := req.ParseForm(); err != nil {
62 return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
63 }
64 if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_TeachingService_GetSchedule_0); err != nil {
65 return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
66 }
67 msg, err := server.GetSchedule(ctx, &protoReq)
68 return msg, metadata, err
69 }
70
71 var filter_TeachingService_GetSchedule_1 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
72
73 func request_TeachingService_GetSchedule_1(ctx context.Context, marshaler runtime.Marshaler, client TeachingServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
74 var (
75 protoReq GetScheduleRequest
Script executed:
rg "server\.GetSchedule\|\.ToGetScheduleResponse" --type go -B 5 -A 10 | head -80Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
Script executed:
find . -type f -name "*.go" ! -name "*pb*" ! -name "*test*" -exec grep -l "GetSchedule\|ToGetScheduleResponse" {} \; | head -10Repository: hduhelp/api_open_sdk
Repository: hduhelp/api_open_sdk
Exit code: 0
stdout:
./campusapis/teaching/v1/courses.go
SemesterStartTimestamp 使用固定常量,查询其他学期时会返回错误的时间戳
GetScheduleRequest 支持指定学年/学期查询(见 proto 注释中的优先级说明),但 ToGetScheduleResponse() 直接使用固定常量 schoolConst.SemesterStartTimestamp,会导致查询历史学期或未来学期时返回错误的时间戳。建议该方法接收正确的学期开始时间戳作为参数,由调用方根据请求的学年/学期计算并传入。
🤖 Prompt for AI Agents
In `@campusapis/teaching/v1/courses.go` around lines 3 - 13, The
ToGetScheduleResponse method currently hardcodes SemesterStartTimestamp using
schoolConst.SemesterStartTimestamp which breaks queries for non-default terms;
change the signature of Courses.ToGetScheduleResponse (the method on type
Courses) to accept a semesterStartTimestamp parameter and set
ScheduleResponseData.SemesterStartTimestamp to that parameter instead of
schoolConst.SemesterStartTimestamp, and update callers to compute/lookup the
correct semester start timestamp based on the GetScheduleRequest (year/term) and
pass it into ToGetScheduleResponse so historical/future term queries return the
correct value.
| "post": { | ||
| "summary": "新增或更新体测成绩", | ||
| "operationId": "FitnessService_StoreFitnessScore2", | ||
| "responses": { | ||
| "200": { | ||
| "description": "A successful response.", | ||
| "schema": { | ||
| "$ref": "#/definitions/v1StoreFitnessScoreResponse" | ||
| } | ||
| }, | ||
| "default": { | ||
| "description": "An unexpected error response.", | ||
| "schema": { | ||
| "$ref": "#/definitions/rpcStatus" | ||
| } | ||
| } | ||
| }, | ||
| "parameters": [ | ||
| { | ||
| "name": "staffId", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "string" | ||
| }, | ||
| { | ||
| "name": "schoolYear", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "string" | ||
| }, | ||
| { | ||
| "name": "semester", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "integer", | ||
| "format": "int32" | ||
| }, | ||
| { | ||
| "name": "gender", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "string" | ||
| }, | ||
| { | ||
| "name": "grade", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "integer", | ||
| "format": "int32" | ||
| }, | ||
| { | ||
| "name": "height", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "number", | ||
| "format": "float" | ||
| }, | ||
| { | ||
| "name": "weight", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "number", | ||
| "format": "float" | ||
| }, | ||
| { | ||
| "name": "bmi", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "number", | ||
| "format": "float" | ||
| }, | ||
| { | ||
| "name": "run50m", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "number", | ||
| "format": "float" | ||
| }, | ||
| { | ||
| "name": "standingLongJump", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "number", | ||
| "format": "float" | ||
| }, | ||
| { | ||
| "name": "sitAndReach", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "number", | ||
| "format": "float" | ||
| }, | ||
| { | ||
| "name": "run800m", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "number", | ||
| "format": "float" | ||
| }, | ||
| { | ||
| "name": "run1000m", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "number", | ||
| "format": "float" | ||
| }, | ||
| { | ||
| "name": "sitUps", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "integer", | ||
| "format": "int32" | ||
| }, | ||
| { | ||
| "name": "pullUps", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "integer", | ||
| "format": "int32" | ||
| }, | ||
| { | ||
| "name": "lungCapacity", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "integer", | ||
| "format": "int32" | ||
| }, | ||
| { | ||
| "name": "totalScore", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "number", | ||
| "format": "float" | ||
| } | ||
| ], | ||
| "tags": [ | ||
| "FitnessService" | ||
| ] |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's find the swagger file and check its structure
find . -type f -name "fitness.swagger.json" 2>/dev/null | head -5Repository: hduhelp/api_open_sdk
Length of output: 121
🏁 Script executed:
# Also check for related proto files
find . -type f -name "*.proto" -path "*fitness*" 2>/dev/null | head -10Repository: hduhelp/api_open_sdk
Length of output: 101
🏁 Script executed:
# Let's examine the swagger file to see the full structure
wc -l docs/swagger/campusapis/fitness/v1/fitness.swagger.jsonRepository: hduhelp/api_open_sdk
Length of output: 123
🏁 Script executed:
# Read the full swagger file to see all endpoints
cat docs/swagger/campusapis/fitness/v1/fitness.swagger.jsonRepository: hduhelp/api_open_sdk
Length of output: 17538
🏁 Script executed:
# Read the proto file to see the endpoint definitions and additional_bindings
cat campusapis/fitness/v1/fitness.protoRepository: hduhelp/api_open_sdk
Length of output: 2958
在 proto 文件中为 additional_bindings 添加 body: "*" 配置
根据 proto 文件分析,StoreFitnessScore 和 UpdateFitnessScore 的 additional_bindings 缺少 body: "*" 配置,导致 Swagger 生成器将这些额外绑定的所有字段解释为 query 参数。这造成:
/fitness/score的 POST 和 PATCH 使用 query 参数/fitness/v1/score的 POST 和 PATCH 使用 body 参数
需要在 proto 中修改:
rpc StoreFitnessScore(StoreFitnessScoreRequest) returns (StoreFitnessScoreResponse) {
option (google.api.http) = {
post: "/fitness/v1/score"
body: "*"
additional_bindings {
post: "/fitness/score"
body: "*" // 添加此行
}
};
}
rpc UpdateFitnessScore(UpdateFitnessScoreRequest) returns (UpdateFitnessScoreResponse) {
option (google.api.http) = {
patch: "/fitness/v1/score"
body: "*"
additional_bindings {
patch: "/fitness/score"
body: "*" // 添加此行
}
};
}修改后重新生成 Swagger 文件。
🧰 Tools
🪛 Checkov (3.2.334)
[medium] 62-199: Ensure that operation objects have 'consumes' field defined for PUT, POST and PATCH operations - version 2.0 files
(CKV_OPENAPI_17)
🤖 Prompt for AI Agents
In `@docs/swagger/campusapis/fitness/v1/fitness.swagger.json` around lines 62 -
199, The Swagger shows POST/PATCH to /fitness/score being rendered as query
params because the proto RPCs StoreFitnessScore and UpdateFitnessScore omitted
body: "*" in their additional_bindings; update both RPC options so each
additional_bindings block for StoreFitnessScore and UpdateFitnessScore includes
body: "*" (matching the primary binding), then regenerate the Swagger to ensure
/fitness/score endpoints use request body instead of query parameters.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@docs/swagger/campusapis/staff/v1/campus.swagger.json`:
- Around line 37-56: The DELETE operation currently has its identifying query
parameters marked as optional; update the parameter definitions for "staffId",
"schoolYear", and "semester" to "required": true in the Swagger spec so callers
must supply them, or preferably add field behavior annotations in the proto
(e.g., google.api.field_behavior = REQUIRED on those fields) and regenerate the
swagger; also add server-side validation in the delete handler to enforce
presence/validity of staffId/schoolYear/semester before performing deletion.
- Around line 19-200: The POST/PATCH endpoints for /fitness/score are using
query params because the proto additional_bindings for StoreFitnessScore and
UpdateFitnessScore lack a body declaration; open the rpc definitions
StoreFitnessScore(StoreFitnessScoreRequest) and
UpdateFitnessScore(UpdateFitnessScoreRequest) in campus.proto and add body: "*"
inside each additional_bindings block that binds to "/fitness/score" (so the
additional_bindings post/patch entries include body: "*"), then regenerate the
swagger so those endpoints accept the request body instead of query parameters.
🧹 Nitpick comments (5)
campusapis/staff/v1/campus.proto (4)
209-241: RPC 定义结构良好,但存在几点设计考虑。
缺少读取操作:有 Store、Update、Delete,但没有
GetFitnessScore用于查询体测成绩。建议补充完整 CRUD 操作。语义重叠:
StoreFitnessScore描述为"新增或更新"(upsert),而UpdateFitnessScore为"更新"。两者功能重叠,可能造成 API 使用者困惑。建议:
- 要么只保留
StoreFitnessScore(upsert 语义)- 要么将
StoreFitnessScore改为纯CreateFitnessScore(仅新增)
871-889: 字段命名风格与文件其他部分不一致。新增的消息使用
snake_case(如staff_id、school_year),而文件中已有消息均使用camelCase(如staffId、schoolYear)。建议保持一致性。♻️ 建议修改为 camelCase
message StoreFitnessScoreRequest { - string staff_id = 1; - string school_year = 2; + string staffId = 1; + string schoolYear = 2; int32 semester = 3; string gender = 4; int32 grade = 5; float height = 6; float weight = 7; float bmi = 8; - float run_50m = 9; - float standing_long_jump = 10; - float sit_and_reach = 11; - float run_800m = 12; - float run_1000m = 13; - int32 sit_ups = 14; - int32 pull_ups = 15; - int32 lung_capacity = 16; - float total_score = 17; + float run50m = 9; + float standingLongJump = 10; + float sitAndReach = 11; + float run800m = 12; + float run1000m = 13; + int32 sitUps = 14; + int32 pullUps = 15; + int32 lungCapacity = 16; + float totalScore = 17; }同样的命名修改也应应用于
UpdateFitnessScoreRequest、DeleteFitnessScoreRequest和FitnessScore消息。
871-917:StoreFitnessScoreRequest和UpdateFitnessScoreRequest字段完全相同,存在代码重复。两个请求消息的字段定义完全一致,违反 DRY 原则。可以考虑:
- 直接复用
FitnessScore消息作为请求体- 或者如果
UpdateFitnessScore需要支持部分更新,考虑使用google.protobuf.FieldMask♻️ 建议复用 FitnessScore
-// StoreFitnessScoreRequest 新增或更新体测成绩请求 -message StoreFitnessScoreRequest { - string staff_id = 1; - // ... 省略重复字段 -} +// StoreFitnessScoreRequest 新增或更新体测成绩请求 +message StoreFitnessScoreRequest { + FitnessScore fitness_score = 1; +} -// UpdateFitnessScoreRequest 更新体测成绩请求 -message UpdateFitnessScoreRequest { - string staff_id = 1; - // ... 省略重复字段 -} +// UpdateFitnessScoreRequest 更新体测成绩请求 +message UpdateFitnessScoreRequest { + FitnessScore fitness_score = 1; + google.protobuf.FieldMask update_mask = 2; // 可选:指定要更新的字段 +}
926-931: 删除请求的关键字段应明确标注为必填。
DeleteFitnessScoreRequest中的staff_id、school_year、semester是定位记录的关键字段,建议在注释中明确说明这些字段为必填,便于 API 使用者理解。♻️ 添加必填说明
// DeleteFitnessScoreRequest 删除体测成绩请求 message DeleteFitnessScoreRequest { - string staff_id = 1; - string school_year = 2; - int32 semester = 3; + // 学工号(必填) + string staff_id = 1; + // 学年(必填) + string school_year = 2; + // 学期(必填) + int32 semester = 3; }docs/swagger/campusapis/staff/v1/campus.swagger.json (1)
62-200: POST 和 PATCH 操作缺少consumes字段定义。根据 OpenAPI 2.0 规范,包含请求体的操作(POST、PATCH、PUT)应定义
consumes字段。虽然文件顶层已定义全局consumes: ["application/json"],但静态分析工具建议在操作级别也明确声明,以提高 API 文档的清晰度。由于这是自动生成的文件,可以考虑配置 gRPC-gateway 或 protoc-gen-openapiv2 插件来添加此字段。
| "/fitness/score": { | ||
| "delete": { | ||
| "summary": "删除体测成绩", | ||
| "operationId": "CampusService_DeleteFitnessScore2", | ||
| "responses": { | ||
| "200": { | ||
| "description": "A successful response.", | ||
| "schema": { | ||
| "$ref": "#/definitions/v1DeleteFitnessScoreResponse" | ||
| } | ||
| }, | ||
| "default": { | ||
| "description": "An unexpected error response.", | ||
| "schema": { | ||
| "$ref": "#/definitions/rpcStatus" | ||
| } | ||
| } | ||
| }, | ||
| "parameters": [ | ||
| { | ||
| "name": "staffId", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "string" | ||
| }, | ||
| { | ||
| "name": "schoolYear", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "string" | ||
| }, | ||
| { | ||
| "name": "semester", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "integer", | ||
| "format": "int32" | ||
| } | ||
| ], | ||
| "tags": [ | ||
| "CampusService" | ||
| ] | ||
| }, | ||
| "post": { | ||
| "summary": "新增或更新体测成绩", | ||
| "operationId": "CampusService_StoreFitnessScore2", | ||
| "responses": { | ||
| "200": { | ||
| "description": "A successful response.", | ||
| "schema": { | ||
| "$ref": "#/definitions/v1StoreFitnessScoreResponse" | ||
| } | ||
| }, | ||
| "default": { | ||
| "description": "An unexpected error response.", | ||
| "schema": { | ||
| "$ref": "#/definitions/rpcStatus" | ||
| } | ||
| } | ||
| }, | ||
| "parameters": [ | ||
| { | ||
| "name": "staffId", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "string" | ||
| }, | ||
| { | ||
| "name": "schoolYear", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "string" | ||
| }, | ||
| { | ||
| "name": "semester", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "integer", | ||
| "format": "int32" | ||
| }, | ||
| { | ||
| "name": "gender", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "string" | ||
| }, | ||
| { | ||
| "name": "grade", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "integer", | ||
| "format": "int32" | ||
| }, | ||
| { | ||
| "name": "height", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "number", | ||
| "format": "float" | ||
| }, | ||
| { | ||
| "name": "weight", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "number", | ||
| "format": "float" | ||
| }, | ||
| { | ||
| "name": "bmi", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "number", | ||
| "format": "float" | ||
| }, | ||
| { | ||
| "name": "run50m", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "number", | ||
| "format": "float" | ||
| }, | ||
| { | ||
| "name": "standingLongJump", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "number", | ||
| "format": "float" | ||
| }, | ||
| { | ||
| "name": "sitAndReach", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "number", | ||
| "format": "float" | ||
| }, | ||
| { | ||
| "name": "run800m", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "number", | ||
| "format": "float" | ||
| }, | ||
| { | ||
| "name": "run1000m", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "number", | ||
| "format": "float" | ||
| }, | ||
| { | ||
| "name": "sitUps", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "integer", | ||
| "format": "int32" | ||
| }, | ||
| { | ||
| "name": "pullUps", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "integer", | ||
| "format": "int32" | ||
| }, | ||
| { | ||
| "name": "lungCapacity", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "integer", | ||
| "format": "int32" | ||
| }, | ||
| { | ||
| "name": "totalScore", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "number", | ||
| "format": "float" | ||
| } | ||
| ], | ||
| "tags": [ | ||
| "CampusService" | ||
| ] | ||
| }, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "campus.proto" -path "*/campusapis/staff/v1/*" | head -5Repository: hduhelp/api_open_sdk
Length of output: 98
🏁 Script executed:
cat ./campusapis/staff/v1/campus.proto | grep -A 20 "DeleteFitnessScore\|StoreFitnessScore"Repository: hduhelp/api_open_sdk
Length of output: 2597
🏁 Script executed:
# Verify the swagger.json reflects the proto misconfiguration
grep -n "\"in\": \"query\"" docs/swagger/campusapis/staff/v1/campus.swagger.json | head -5
grep -n "\"in\": \"body\"" docs/swagger/campusapis/staff/v1/campus.swagger.json | head -5Repository: hduhelp/api_open_sdk
Length of output: 273
/fitness/score 的 POST/PATCH 操作需要修复 proto 配置中的 body 声明。
/fitness/score 的 POST 和 PATCH 操作使用 query 参数传递所有字段,而 /staff/v1/fitness/score 使用 body 传递。根本原因在于 proto 文件中,这两个操作的 additional_bindings 缺少 body: "*" 声明。
在 campusapis/staff/v1/campus.proto 中修改:
rpc StoreFitnessScore(StoreFitnessScoreRequest) returns (StoreFitnessScoreResponse) {
option (google.api.http) = {
post: "/staff/v1/fitness/score"
body: "*"
additional_bindings {
post: "/fitness/score"
body: "*" // 添加此行
}
};
}
rpc UpdateFitnessScore(UpdateFitnessScoreRequest) returns (UpdateFitnessScoreResponse) {
option (google.api.http) = {
patch: "/staff/v1/fitness/score"
body: "*"
additional_bindings {
patch: "/fitness/score"
body: "*" // 添加此行
}
};
}
使用 query 参数传递 POST/PATCH 请求会导致敏感数据暴露在 URL 中(日志、浏览器历史等),违反 REST 最佳实践,且两个端点行为不一致。
🧰 Tools
🪛 Checkov (3.2.334)
[medium] 62-199: Ensure that operation objects have 'consumes' field defined for PUT, POST and PATCH operations - version 2.0 files
(CKV_OPENAPI_17)
🤖 Prompt for AI Agents
In `@docs/swagger/campusapis/staff/v1/campus.swagger.json` around lines 19 - 200,
The POST/PATCH endpoints for /fitness/score are using query params because the
proto additional_bindings for StoreFitnessScore and UpdateFitnessScore lack a
body declaration; open the rpc definitions
StoreFitnessScore(StoreFitnessScoreRequest) and
UpdateFitnessScore(UpdateFitnessScoreRequest) in campus.proto and add body: "*"
inside each additional_bindings block that binds to "/fitness/score" (so the
additional_bindings post/patch entries include body: "*"), then regenerate the
swagger so those endpoints accept the request body instead of query parameters.
| "parameters": [ | ||
| { | ||
| "name": "staffId", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "string" | ||
| }, | ||
| { | ||
| "name": "schoolYear", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "string" | ||
| }, | ||
| { | ||
| "name": "semester", | ||
| "in": "query", | ||
| "required": false, | ||
| "type": "integer", | ||
| "format": "int32" | ||
| } |
There was a problem hiding this comment.
删除操作的关键参数应标记为必填。
staffId、schoolYear、semester 是定位要删除记录的必要参数,但当前都标记为 "required": false。这可能导致调用者遗漏必要参数,造成意外行为。
由于这是自动生成的 Swagger 文件,应在 proto 定义中通过注释或 proto 选项来控制必填性,或在服务实现中增加校验。
🤖 Prompt for AI Agents
In `@docs/swagger/campusapis/staff/v1/campus.swagger.json` around lines 37 - 56,
The DELETE operation currently has its identifying query parameters marked as
optional; update the parameter definitions for "staffId", "schoolYear", and
"semester" to "required": true in the Swagger spec so callers must supply them,
or preferably add field behavior annotations in the proto (e.g.,
google.api.field_behavior = REQUIRED on those fields) and regenerate the
swagger; also add server-side validation in the delete handler to enforce
presence/validity of staffId/schoolYear/semester before performing deletion.
Summary by CodeRabbit
发布说明
✏️ Tip: You can customize this high-level summary in your review settings.