feat: added API gateway
This commit is contained in:
@@ -0,0 +1,291 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"datarush/internal/gw/domain"
|
||||
|
||||
achievepb "datarush/pkg/api/achievements"
|
||||
comppb "datarush/pkg/api/competition"
|
||||
resultspb "datarush/pkg/api/results"
|
||||
reviewpb "datarush/pkg/api/review"
|
||||
subpb "datarush/pkg/api/submission"
|
||||
taskpb "datarush/pkg/api/task"
|
||||
userpb "datarush/pkg/api/user"
|
||||
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
func UserProtoToHTTP(u *userpb.User) *domain.UserResponse {
|
||||
return &domain.UserResponse{
|
||||
ID: u.Id,
|
||||
Username: u.Username,
|
||||
Email: u.Email,
|
||||
FullName: u.FullName,
|
||||
AvatarURL: u.AvatarUrl,
|
||||
}
|
||||
}
|
||||
|
||||
func CompetitionProtoToHTTP(c *comppb.Competition) *domain.CompetitionResponse {
|
||||
return &domain.CompetitionResponse{
|
||||
ID: c.Id,
|
||||
State: CompetitionStateToString(c.State),
|
||||
Title: c.Title,
|
||||
Description: c.Description,
|
||||
ImageURL: c.ImageUrl,
|
||||
StartTime: c.StartTime.AsTime(),
|
||||
EndTime: c.EndTime.AsTime(),
|
||||
Type: CompetitionTypeToString(c.Type),
|
||||
ParticipationType: ParticipationTypeToString(c.ParticipationType),
|
||||
CreatedAt: c.CreatedAt.AsTime(),
|
||||
UpdatedAt: c.UpdatedAt.AsTime(),
|
||||
}
|
||||
}
|
||||
|
||||
func TaskProtoToHTTP(t *taskpb.Task) *domain.TaskResponse {
|
||||
return &domain.TaskResponse{
|
||||
ID: t.Id,
|
||||
CompetitionID: t.CompetitionId,
|
||||
Title: t.Title,
|
||||
Description: t.Description,
|
||||
InCompetitionPosition: t.InCompetitionPosition,
|
||||
MaxPoints: t.MaxPoints,
|
||||
MaxAttempts: t.MaxAttempts,
|
||||
Type: TaskTypeToString(t.Type),
|
||||
CreatedAt: t.CreatedAt.AsTime(),
|
||||
UpdatedAt: t.UpdatedAt.AsTime(),
|
||||
}
|
||||
}
|
||||
|
||||
func SubmissionProtoToHTTP(s *subpb.Submission) *domain.SubmissionResponse {
|
||||
return &domain.SubmissionResponse{
|
||||
ID: s.Id,
|
||||
UserID: s.UserId,
|
||||
CompetitionID: s.CompetitionId,
|
||||
TaskID: s.TaskId,
|
||||
Status: SubmissionStatusToString(s.Status),
|
||||
EarnedPoints: s.EarnedPoints,
|
||||
SubmittedAt: s.SubmittedAt.AsTime(),
|
||||
CheckedAt: s.CheckedAt.AsTime(),
|
||||
FileURL: s.FileUrl,
|
||||
}
|
||||
}
|
||||
|
||||
func UserResultProtoToHTTP(r *resultspb.UserResult) *domain.UserResultResponse {
|
||||
taskStatuses := make([]domain.TaskStatusResponse, len(r.TaskStatuses))
|
||||
for i, ts := range r.TaskStatuses {
|
||||
taskStatuses[i] = domain.TaskStatusResponse{
|
||||
TaskID: ts.TaskId,
|
||||
TaskTitle: ts.TaskTitle,
|
||||
EarnedPoints: ts.EarnedPoints,
|
||||
MaxPoints: ts.MaxPoints,
|
||||
Position: ts.Position,
|
||||
}
|
||||
}
|
||||
|
||||
return &domain.UserResultResponse{
|
||||
UserID: r.UserId,
|
||||
Username: r.Username,
|
||||
TotalScore: r.TotalScore,
|
||||
OverallPosition: r.OverallPosition,
|
||||
TaskStatuses: taskStatuses,
|
||||
}
|
||||
}
|
||||
|
||||
func SubmissionSummaryProtoToHTTP(s *reviewpb.SubmissionSummary) *domain.SubmissionSummaryResponse {
|
||||
return &domain.SubmissionSummaryResponse{
|
||||
ID: s.Id,
|
||||
CompetitionID: s.CompetitionId,
|
||||
TaskID: s.TaskId,
|
||||
CompetitionTitle: s.CompetitionTitle,
|
||||
TaskTitle: s.TaskTitle,
|
||||
SubmittedAt: s.SubmittedAt.AsTime(),
|
||||
ReviewStatus: ReviewStatusToString(s.ReviewStatus),
|
||||
}
|
||||
}
|
||||
|
||||
func SubmissionForReviewProtoToHTTP(s *reviewpb.SubmissionForReview) *domain.SubmissionForReviewResponse {
|
||||
resp := &domain.SubmissionForReviewResponse{
|
||||
ID: s.Id,
|
||||
CompetitionID: s.CompetitionId,
|
||||
TaskID: s.TaskId,
|
||||
Content: s.Content,
|
||||
Description: s.Description,
|
||||
ReviewStatus: ReviewStatusToString(s.ReviewStatus),
|
||||
SubmittedAt: s.SubmittedAt.AsTime(),
|
||||
}
|
||||
if s.CheckedAt != nil {
|
||||
t := s.CheckedAt.AsTime()
|
||||
resp.CheckedAt = &t
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
func AchievementProtoToHTTP(a *achievepb.Achievement) *domain.AchievementResponse {
|
||||
return &domain.AchievementResponse{
|
||||
ID: a.Id,
|
||||
Name: a.Name,
|
||||
Description: a.Description,
|
||||
IconURL: a.IconUrl,
|
||||
}
|
||||
}
|
||||
|
||||
func CompetitionHTTPToProto(req *domain.CompetitionRequest) *comppb.Competition {
|
||||
return &comppb.Competition{
|
||||
Id: req.ID,
|
||||
Title: req.Title,
|
||||
Description: req.Description,
|
||||
ImageUrl: req.ImageURL,
|
||||
StartTime: timestamppb.New(req.StartTime),
|
||||
EndTime: timestamppb.New(req.EndTime),
|
||||
Type: StringToCompetitionType(req.Type),
|
||||
ParticipationType: StringToParticipationType(req.ParticipationType),
|
||||
}
|
||||
}
|
||||
|
||||
func TaskHTTPToProto(req *domain.TaskRequest) *taskpb.Task {
|
||||
return &taskpb.Task{
|
||||
Id: req.ID,
|
||||
CompetitionId: req.CompetitionID,
|
||||
Title: req.Title,
|
||||
Description: req.Description,
|
||||
InCompetitionPosition: req.InCompetitionPosition,
|
||||
MaxPoints: req.MaxPoints,
|
||||
MaxAttempts: req.MaxAttempts,
|
||||
Type: StringToTaskType(req.Type),
|
||||
}
|
||||
}
|
||||
|
||||
func CompetitionStateToString(state comppb.CompetitionState) string {
|
||||
switch state {
|
||||
case comppb.CompetitionState_COMPETITION_STATE_DRAFT:
|
||||
return "draft"
|
||||
case comppb.CompetitionState_COMPETITION_STATE_NOT_STARTED:
|
||||
return "not_started"
|
||||
case comppb.CompetitionState_COMPETITION_STATE_STARTED:
|
||||
return "started"
|
||||
case comppb.CompetitionState_COMPETITION_STATE_FINISHED:
|
||||
return "finished"
|
||||
case comppb.CompetitionState_COMPETITION_STATE_ARCHIVED:
|
||||
return "archived"
|
||||
default:
|
||||
return "unspecified"
|
||||
}
|
||||
}
|
||||
|
||||
func StringToCompetitionState(state string) comppb.CompetitionState {
|
||||
switch state {
|
||||
case "draft":
|
||||
return comppb.CompetitionState_COMPETITION_STATE_DRAFT
|
||||
case "not_started":
|
||||
return comppb.CompetitionState_COMPETITION_STATE_NOT_STARTED
|
||||
case "started":
|
||||
return comppb.CompetitionState_COMPETITION_STATE_STARTED
|
||||
case "finished":
|
||||
return comppb.CompetitionState_COMPETITION_STATE_FINISHED
|
||||
case "archived":
|
||||
return comppb.CompetitionState_COMPETITION_STATE_ARCHIVED
|
||||
default:
|
||||
return comppb.CompetitionState_COMPETITION_STATE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func CompetitionTypeToString(t comppb.CompetitionType) string {
|
||||
switch t {
|
||||
case comppb.CompetitionType_COMPETITION_TYPE_EDUCATIVE:
|
||||
return "educative"
|
||||
case comppb.CompetitionType_COMPETITION_TYPE_COMPETETIVE:
|
||||
return "competitive"
|
||||
default:
|
||||
return "unspecified"
|
||||
}
|
||||
}
|
||||
|
||||
func StringToCompetitionType(t string) comppb.CompetitionType {
|
||||
switch t {
|
||||
case "educative":
|
||||
return comppb.CompetitionType_COMPETITION_TYPE_EDUCATIVE
|
||||
case "competitive":
|
||||
return comppb.CompetitionType_COMPETITION_TYPE_COMPETETIVE
|
||||
default:
|
||||
return comppb.CompetitionType_COMPETITION_TYPE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func ParticipationTypeToString(t comppb.ParticipationType) string {
|
||||
switch t {
|
||||
case comppb.ParticipationType_PARTICIPATION_TYPE_INDIVIDUAL:
|
||||
return "individual"
|
||||
case comppb.ParticipationType_PARTICIPATION_TYPE_TEAM:
|
||||
return "team"
|
||||
default:
|
||||
return "unspecified"
|
||||
}
|
||||
}
|
||||
|
||||
func StringToParticipationType(t string) comppb.ParticipationType {
|
||||
switch t {
|
||||
case "individual":
|
||||
return comppb.ParticipationType_PARTICIPATION_TYPE_INDIVIDUAL
|
||||
case "team":
|
||||
return comppb.ParticipationType_PARTICIPATION_TYPE_TEAM
|
||||
default:
|
||||
return comppb.ParticipationType_PARTICIPATION_TYPE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func TaskTypeToString(t taskpb.TaskType) string {
|
||||
switch t {
|
||||
case taskpb.TaskType_TASK_TYPE_INPUT:
|
||||
return "input"
|
||||
case taskpb.TaskType_TASK_TYPE_CHECKER:
|
||||
return "checker"
|
||||
case taskpb.TaskType_TASK_TYPE_REVIEW:
|
||||
return "review"
|
||||
default:
|
||||
return "unspecified"
|
||||
}
|
||||
}
|
||||
|
||||
func StringToTaskType(t string) taskpb.TaskType {
|
||||
switch t {
|
||||
case "input":
|
||||
return taskpb.TaskType_TASK_TYPE_INPUT
|
||||
case "checker":
|
||||
return taskpb.TaskType_TASK_TYPE_CHECKER
|
||||
case "review":
|
||||
return taskpb.TaskType_TASK_TYPE_REVIEW
|
||||
default:
|
||||
return taskpb.TaskType_TASK_TYPE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func SubmissionStatusToString(s subpb.SubmissionStatus) string {
|
||||
switch s {
|
||||
case subpb.SubmissionStatus_SUBMISSION_STATUS_PENDING:
|
||||
return "pending"
|
||||
case subpb.SubmissionStatus_SUBMISSION_STATUS_SENT_FOR_CHECK:
|
||||
return "sent"
|
||||
case subpb.SubmissionStatus_SUBMISSION_STATUS_CHECKING:
|
||||
return "checking"
|
||||
case subpb.SubmissionStatus_SUBMISSION_STATUS_CHECKED:
|
||||
return "checked"
|
||||
case subpb.SubmissionStatus_SUBMISSION_STATUS_FAILED:
|
||||
return "failed"
|
||||
default:
|
||||
return "unspecified"
|
||||
}
|
||||
}
|
||||
|
||||
func ReviewStatusToString(s reviewpb.ReviewStatus) string {
|
||||
switch s {
|
||||
case reviewpb.ReviewStatus_REVIEW_STATUS_PENDING:
|
||||
return "pending"
|
||||
case reviewpb.ReviewStatus_REVIEW_STATUS_IN_REVIEW:
|
||||
return "in_review"
|
||||
case reviewpb.ReviewStatus_REVIEW_STATUS_COMPLETED:
|
||||
return "completed"
|
||||
case reviewpb.ReviewStatus_REVIEW_STATUS_REJECTED:
|
||||
return "rejected"
|
||||
default:
|
||||
return "unspecified"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"datarush/internal/gw/domain"
|
||||
)
|
||||
|
||||
func RespondJSON(w http.ResponseWriter, statusCode int, data interface{}) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(statusCode)
|
||||
|
||||
if data != nil {
|
||||
if err := json.NewEncoder(w).Encode(data); err != nil {
|
||||
http.Error(w, "internal server error", http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func RespondError(w http.ResponseWriter, err error) {
|
||||
if appErr, ok := err.(*domain.AppError); ok {
|
||||
RespondJSON(w, appErr.StatusCode, domain.NewErrorResponse(appErr.Err, appErr.Message))
|
||||
return
|
||||
}
|
||||
|
||||
RespondJSON(w, http.StatusInternalServerError, domain.NewErrorResponse(err, "internal server error"))
|
||||
}
|
||||
|
||||
func DecodeJSON(r *http.Request, v interface{}) error {
|
||||
if err := json.NewDecoder(r.Body).Decode(v); err != nil {
|
||||
return domain.NewBadRequestError("invalid JSON body")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user