Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ Recipes are grouped into namespaced modules (`tools/just/*.just`) addressed with
After changing `*.proto` use `just api-change`; after changing `db/schema/*.go`
use `just schema-change`; `just changes` will tell you which you need.

> Note: `just api-change` depends on `protoc-gen-ts_proto` which is installed by
> the frontend. You must build the frontend once before calling
> `just api-change` for the first time.

## Versioning

`VERSION` at the repo root holds the product version, and it is the only place
Expand Down
3 changes: 2 additions & 1 deletion api/proto/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -5106,6 +5106,7 @@ casbin role for this hackathon; `is_waiting` is false once approved.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| team_id | [string](#string) | | |
| hackathon_id | [string](#string) | | |



Expand Down Expand Up @@ -5136,7 +5137,7 @@ casbin role for this hackathon; `is_waiting` is false once approved.

| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| submissions | [hackathon.entities.Submission](#hackathon-entities-Submission) | repeated | |
| submissions | [hackathon.entities.Submission](#hackathon-entities-Submission) | repeated | Ordered by team_id ascending, then by version ascending (oldest first). (team_id, version) is unique, so the order is total. |



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@ syntax = "proto3";

package hackathon.messages.team_svc;

import "buf/validate/validate.proto";

option go_package = "github.com/swissdatasciencecenter/hackagon/components/backend/internal/proto/hackathon/messages/team_svc";

message ListSubmissionsRequest {
string team_id = 1;
oneof value {
string team_id = 1 [(buf.validate.field).string.uuid = true];
string hackathon_id = 2 [(buf.validate.field).string.uuid = true];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@ import "hackathon/entities/submission.proto";
option go_package = "github.com/swissdatasciencecenter/hackagon/components/backend/internal/proto/hackathon/messages/team_svc";

message ListSubmissionsResponse {
// Ordered by team_id ascending, then by version ascending (oldest first).
// (team_id, version) is unique, so the order is total.
repeated hackathon.entities.Submission submissions = 1;
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

83 changes: 64 additions & 19 deletions components/backend/internal/service/team_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -1081,39 +1081,84 @@ func (s *TeamService) ListSubmissions(
ctx context.Context,
req *msgs.ListSubmissionsRequest,
) (*msgs.ListSubmissionsResponse, error) {
teamID, err := uuid.Parse(req.GetTeamId())
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid team_id: %v", err)
}
query := s.dbClient.Submission.Query()

t, err := getTeamById(ctx, s, teamID)
if err != nil {
return nil, err
}
switch req.GetValue().(type) {
case *msgs.ListSubmissionsRequest_TeamId:
teamID, err := uuid.Parse(req.GetTeamId())
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid team_id: %v", err)
}

if t.Edges.Project == nil || t.Edges.Project.Edges.Hackathon == nil {
return nil, status.Error(codes.Internal, "team project or hackathon not found")
}
t, err := getTeamById(ctx, s, teamID)
if err != nil {
return nil, err
}

hackathonID := t.Edges.Project.Edges.Hackathon.ID.String()
if err := s.enforcer.RequirePermission(
ctx, hackathonID, m.Submission, m.Read,
m.WithTeam(t.ID.String()),
); err != nil {
if t.Edges.Project == nil || t.Edges.Project.Edges.Hackathon == nil {
return nil, status.Error(codes.Internal, "team project or hackathon not found")
}

// Team members read their own team; owners hold submission:read
// hackathon-wide.
hackathonID := t.Edges.Project.Edges.Hackathon.ID.String()
if err := s.enforcer.RequirePermission(
ctx, hackathonID, m.Submission, m.Read,
m.WithTeam(t.ID.String()),
); err != nil {
if err := s.enforcer.RequirePermission(
ctx, hackathonID, m.Submission, m.Read,
); err != nil {
return nil, err
}
}

query = query.Where(entsubmission.HasTeamWith(entteam.IDEQ(teamID)))

case *msgs.ListSubmissionsRequest_HackathonId:
hackathonID, err := uuid.Parse(req.GetHackathonId())
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid hackathon_id: %v", err)
}

// If the hackathon doesn't exist we still return access denied. We do this
// to avoid giving unnecessary information to unauthorized users.
if err := s.enforcer.RequirePermission(
ctx, hackathonID.String(), m.Submission, m.Read,
); err != nil {
return nil, err
}

exists, err := s.dbClient.Hackathon.Query().Where(enthackathon.IDEQ(hackathonID)).Exist(ctx)
if err != nil {
slog.Error("query hackathon", "err", err)

return nil, status.Error(codes.Internal, "couldn't query database")
}
if !exists {
return nil, status.Errorf(codes.NotFound, "hackathon %s not found", hackathonID)
}

query = query.Where(entsubmission.HasTeamWith(
entteam.HasProjectWith(entproject.HasHackathonWith(enthackathon.IDEQ(hackathonID))),
))

default:
return nil, status.Error(
codes.InvalidArgument,
"one of team_id or hackathon_id is required",
)
}

submissions, err := s.dbClient.Submission.Query().
Where(entsubmission.HasTeamWith(entteam.IDEQ(teamID))).
submissions, err := query.
WithTeam().
WithProject().
WithCreator().
WithModifier().
Order(ent.Asc(entsubmission.FieldVersion)).
Order(
ent.Asc(entsubmission.TeamColumn),
ent.Asc(entsubmission.FieldVersion),
).
All(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "query submissions: %v", err)
Expand Down
Loading
Loading