feat: implement submission lifecycle management with creation, review, and status tracking services
All checks were successful
Build and Release / release (push) Successful in 1m29s

This commit is contained in:
2026-05-24 12:58:30 +07:00
parent ae8028549e
commit 9dacfd036d
4 changed files with 780 additions and 535 deletions

View File

@@ -205,3 +205,14 @@ LEFT JOIN users ru ON s.reviewed_by = ru.id
LEFT JOIN user_profiles rup ON ru.id = rup.user_id
WHERE s.id = ANY($1::uuid[]) AND s.is_deleted = false;
-- name: GetLatestApprovedSubmissionExcluding :one
SELECT
id, project_id, commit_id, user_id, created_at, status, reviewed_by, reviewed_at, review_note, content, is_deleted
FROM submissions
WHERE project_id = $1
AND status = 2
AND id != $2
AND is_deleted = false
ORDER BY reviewed_at DESC, created_at DESC
LIMIT 1;

View File

@@ -159,6 +159,56 @@ func (q *Queries) DeleteSubmission(ctx context.Context, id pgtype.UUID) error {
return err
}
const getLatestApprovedSubmissionExcluding = `-- name: GetLatestApprovedSubmissionExcluding :one
SELECT
id, project_id, commit_id, user_id, created_at, status, reviewed_by, reviewed_at, review_note, content, is_deleted
FROM submissions
WHERE project_id = $1
AND status = 2
AND id != $2
AND is_deleted = false
ORDER BY reviewed_at DESC, created_at DESC
LIMIT 1
`
type GetLatestApprovedSubmissionExcludingParams struct {
ProjectID pgtype.UUID `json:"project_id"`
ID pgtype.UUID `json:"id"`
}
type GetLatestApprovedSubmissionExcludingRow struct {
ID pgtype.UUID `json:"id"`
ProjectID pgtype.UUID `json:"project_id"`
CommitID pgtype.UUID `json:"commit_id"`
UserID pgtype.UUID `json:"user_id"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
Status int16 `json:"status"`
ReviewedBy pgtype.UUID `json:"reviewed_by"`
ReviewedAt pgtype.Timestamptz `json:"reviewed_at"`
ReviewNote pgtype.Text `json:"review_note"`
Content pgtype.Text `json:"content"`
IsDeleted bool `json:"is_deleted"`
}
func (q *Queries) GetLatestApprovedSubmissionExcluding(ctx context.Context, arg GetLatestApprovedSubmissionExcludingParams) (GetLatestApprovedSubmissionExcludingRow, error) {
row := q.db.QueryRow(ctx, getLatestApprovedSubmissionExcluding, arg.ProjectID, arg.ID)
var i GetLatestApprovedSubmissionExcludingRow
err := row.Scan(
&i.ID,
&i.ProjectID,
&i.CommitID,
&i.UserID,
&i.CreatedAt,
&i.Status,
&i.ReviewedBy,
&i.ReviewedAt,
&i.ReviewNote,
&i.Content,
&i.IsDeleted,
)
return i, err
}
const getSubmissionById = `-- name: GetSubmissionById :one
SELECT
s.id, s.project_id, s.commit_id, s.user_id, s.created_at, s.status, s.reviewed_by, s.reviewed_at, s.review_note, s.content, s.is_deleted,

View File

@@ -23,6 +23,7 @@ type SubmissionRepository interface {
Create(ctx context.Context, params sqlc.CreateSubmissionParams) (*models.SubmissionEntity, error)
Update(ctx context.Context, params sqlc.UpdateSubmissionParams) (*models.SubmissionEntity, error)
Delete(ctx context.Context, id pgtype.UUID) error
GetLatestApprovedSubmissionExcluding(ctx context.Context, projectID pgtype.UUID, id pgtype.UUID) (*models.SubmissionEntity, error)
WithTx(tx pgx.Tx) SubmissionRepository
}
@@ -323,3 +324,28 @@ func (r *submissionRepository) Delete(ctx context.Context, id pgtype.UUID) error
}()
return nil
}
func (r *submissionRepository) GetLatestApprovedSubmissionExcluding(ctx context.Context, projectID pgtype.UUID, id pgtype.UUID) (*models.SubmissionEntity, error) {
row, err := r.q.GetLatestApprovedSubmissionExcluding(ctx, sqlc.GetLatestApprovedSubmissionExcludingParams{
ProjectID: projectID,
ID: id,
})
if err != nil {
return nil, err
}
entity := &models.SubmissionEntity{
ID: convert.UUIDToString(row.ID),
ProjectID: convert.UUIDToString(row.ProjectID),
CommitID: convert.UUIDToString(row.CommitID),
UserID: convert.UUIDToString(row.UserID),
CreatedAt: convert.TimeToPtr(row.CreatedAt),
Status: constants.ParseStatusType(row.Status),
ReviewedBy: convert.UUIDToStringPtr(row.ReviewedBy),
ReviewedAt: convert.TimeToPtr(row.ReviewedAt),
ReviewNote: convert.TextToPtr(row.ReviewNote),
Content: convert.TextToPtr(row.Content),
IsDeleted: row.IsDeleted,
}
return entity, nil
}

File diff suppressed because it is too large Load Diff