-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
349 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
DROP TABLE IF EXISTS Reports; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
CREATE TABLE Reports ( | ||
ID BIGINT UNSIGNED AUTO_INCREMENT, | ||
|
||
Picture TEXT NOT NULL, | ||
Description TEXT NOT NULL, | ||
Location TEXT NOT NULL, | ||
Action ENUM('PENDING', 'APPROVED', 'REJECTED') NOT NULL DEFAULT 'PENDING', | ||
CreatedAt DATETIME NOT NULL DEFAULT NOW(), | ||
|
||
PRIMARY KEY (ID) | ||
) ENGINE = INNODB DEFAULT CHARSET = UTF8; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package rest | ||
|
||
import ( | ||
"strconv" | ||
|
||
"github.com/go-playground/validator/v10" | ||
"github.com/gofiber/fiber/v2" | ||
"github.com/mirzahilmi/hackathon/internal/model" | ||
"github.com/mirzahilmi/hackathon/internal/usecase" | ||
) | ||
|
||
type ReportHandler struct { | ||
reportUsecase usecase.ReportUsecaseItf | ||
validator *validator.Validate | ||
} | ||
|
||
func RegisterReportHandler( | ||
usecase usecase.ReportUsecaseItf, | ||
validator *validator.Validate, | ||
router fiber.Router, | ||
) { | ||
reportHandler := ReportHandler{usecase, validator} | ||
router = router.Group("/reports") | ||
router.Post("", reportHandler.CreateReport) | ||
router.Get("", reportHandler.GetReports) | ||
router.Patch("/:id<int>", reportHandler.UpdateReport) | ||
} | ||
|
||
func (h *ReportHandler) CreateReport(c *fiber.Ctx) error { | ||
pict, err := c.FormFile("picture") | ||
if err != nil { | ||
return err | ||
} | ||
|
||
req := model.ReportRequest{ | ||
Picture: pict, | ||
Description: c.FormValue("description"), | ||
Location: c.FormValue("location"), | ||
} | ||
if err := h.validator.Struct(&req); err != nil { | ||
return err | ||
} | ||
if err := h.reportUsecase.CreateReport(c.Context(), req); err != nil { | ||
return err | ||
} | ||
return c.Status(fiber.StatusOK).JSON(fiber.Map{"message": "Report created"}) | ||
} | ||
|
||
func (h *ReportHandler) GetReports(c *fiber.Ctx) error { | ||
reports, err := h.reportUsecase.GetReports(c.Context()) | ||
if err != nil { | ||
return err | ||
} | ||
return c.Status(fiber.StatusOK).JSON(reports) | ||
} | ||
|
||
func (h *ReportHandler) UpdateReport(c *fiber.Ctx) error { | ||
id, err := strconv.ParseInt(c.Params("id"), 10, 64) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
value := c.Query("action") | ||
if err := h.reportUsecase.UpdateReport(c.Context(), id, value); err != nil { | ||
return err | ||
} | ||
return c.Status(fiber.StatusOK).JSON(fiber.Map{"message": "Report updated"}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package model | ||
|
||
import "mime/multipart" | ||
|
||
type ReportResource struct { | ||
ID int64 `json:"id" db:"ID"` | ||
Picture string `json:"picture" db:"Picture"` | ||
Description string `json:"description" db:"Description"` | ||
Location string `json:"location" db:"Location"` | ||
CreatedAt string `json:"createdAt" db:"CreatedAt"` | ||
Action string `json:"action" db:"Action"` | ||
} | ||
|
||
type ReportRequest struct { | ||
Picture *multipart.FileHeader `form:"picture" validate:"required"` | ||
Description string `form:"description" validate:"required"` | ||
Location string `form:"location" validate:"required"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package repository | ||
|
||
import ( | ||
"context" | ||
"log" | ||
|
||
"github.com/gofiber/fiber/v2" | ||
"github.com/jmoiron/sqlx" | ||
"github.com/mirzahilmi/hackathon/internal/model" | ||
) | ||
|
||
type ReportRepositoryItf interface { | ||
NewClient(withTx bool, tx sqlx.ExtContext) (ReportQueryerItf, error) | ||
} | ||
|
||
type ReportRepository struct { | ||
db *sqlx.DB | ||
} | ||
|
||
func NewReportRepository(db *sqlx.DB) ReportRepositoryItf { | ||
return &ReportRepository{db} | ||
} | ||
|
||
type ReportQueryerItf interface { | ||
txCompat | ||
CreateReport(ctx context.Context, report *model.ReportResource) error | ||
GetReports(ctx context.Context) ([]model.ReportResource, error) | ||
UpdateActionReport(ctx context.Context, report *model.ReportResource) error | ||
GetReportByID(ctx context.Context, id int64) (model.ReportResource, error) | ||
} | ||
|
||
type reportQueryer struct { | ||
ext sqlx.ExtContext | ||
} | ||
|
||
func (r *ReportRepository) NewClient(withTx bool, tx sqlx.ExtContext) (ReportQueryerItf, error) { | ||
if withTx { | ||
if tx != nil { | ||
return &reportQueryer{tx}, nil | ||
} | ||
tx, err := r.db.Beginx() | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &reportQueryer{tx}, nil | ||
} | ||
return &reportQueryer{r.db}, nil | ||
} | ||
|
||
func (q *reportQueryer) Commit() error { | ||
tx, ok := q.ext.(*sqlx.Tx) | ||
if !ok { | ||
return ErrNotTransaction | ||
} | ||
return tx.Commit() | ||
} | ||
|
||
func (q *reportQueryer) Rollback() error { | ||
tx, ok := q.ext.(*sqlx.Tx) | ||
if !ok { | ||
return ErrNotTransaction | ||
} | ||
return tx.Rollback() | ||
} | ||
|
||
func (q *reportQueryer) Ext() sqlx.ExtContext { | ||
return q.ext | ||
} | ||
|
||
func (q *reportQueryer) CreateReport(ctx context.Context, report *model.ReportResource) error { | ||
query, args, err := sqlx.Named(qCreateReport, fiber.Map{ | ||
"Picture": report.Picture, | ||
"Description": report.Description, | ||
"Location": report.Location, | ||
}) | ||
log.Println(query) | ||
log.Println(args) | ||
if err != nil { | ||
return err | ||
} | ||
_, err = q.ext.ExecContext(ctx, query, args...) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func (q *reportQueryer) GetReports(ctx context.Context) ([]model.ReportResource, error) { | ||
var reports []model.ReportResource | ||
if err := sqlx.SelectContext(ctx, q.ext, &reports, qGetReports); err != nil { | ||
return nil, err | ||
} | ||
return reports, nil | ||
} | ||
|
||
func (q *reportQueryer) UpdateActionReport(ctx context.Context, report *model.ReportResource) error { | ||
query, args, err := sqlx.Named(qUpdateReport, fiber.Map{ | ||
"Action": report.Action, | ||
"ID": report.ID, | ||
}) | ||
if err != nil { | ||
return err | ||
} | ||
_, err = q.ext.ExecContext(ctx, query, args...) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func (q *reportQueryer) GetReportByID(ctx context.Context, id int64) (model.ReportResource, error) { | ||
var report model.ReportResource | ||
if err := sqlx.GetContext(ctx, q.ext, &report, qGetReportByID, id); err != nil { | ||
return model.ReportResource{}, err | ||
} | ||
return report, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package usecase | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"log" | ||
"os" | ||
"time" | ||
|
||
"github.com/mirzahilmi/hackathon/internal/model" | ||
"github.com/mirzahilmi/hackathon/internal/repository" | ||
storage_go "github.com/supabase-community/storage-go" | ||
) | ||
|
||
type ReportUsecaseItf interface { | ||
CreateReport(ctx context.Context, req model.ReportRequest) error | ||
GetReports(ctx context.Context) ([]model.ReportResource, error) | ||
UpdateReport(ctx context.Context, id int64, action string) error | ||
} | ||
|
||
type ReportUsecase struct { | ||
reportRepo repository.ReportRepositoryItf | ||
supabase *storage_go.Client | ||
} | ||
|
||
func NewReportUsecase(reportRepo repository.ReportRepositoryItf, supabase *storage_go.Client) ReportUsecaseItf { | ||
return &ReportUsecase{reportRepo, supabase} | ||
} | ||
|
||
func (u *ReportUsecase) CreateReport(ctx context.Context, req model.ReportRequest) error { | ||
client, err := u.reportRepo.NewClient(true, nil) | ||
if err != nil { | ||
return err | ||
} | ||
defer client.Rollback() | ||
|
||
req.Picture.Filename = fmt.Sprintf("%d_%s", time.Now().UnixMilli(), req.Picture.Filename) | ||
pict, err := req.Picture.Open() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
_, err = u.supabase.UploadFile(os.Getenv("SUPABASE_BUCKET_ID"), req.Picture.Filename, pict) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
pictUrl := u.supabase.GetPublicUrl(os.Getenv("SUPABASE_BUCKET_ID"), req.Picture.Filename) | ||
report := model.ReportResource{ | ||
Picture: pictUrl.SignedURL, | ||
Description: req.Description, | ||
Location: req.Location, | ||
} | ||
log.Println(report) | ||
if err := client.CreateReport(ctx, &report); err != nil { | ||
return err | ||
} | ||
|
||
return client.Commit() | ||
} | ||
|
||
func (u *ReportUsecase) GetReports(ctx context.Context) ([]model.ReportResource, error) { | ||
client, err := u.reportRepo.NewClient(false, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
reports, err := client.GetReports(ctx) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return reports, nil | ||
} | ||
|
||
func (u *ReportUsecase) UpdateReport(ctx context.Context, id int64, action string) error { | ||
client, err := u.reportRepo.NewClient(true, nil) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
report, err := client.GetReportByID(ctx, id) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
report.Action = action | ||
if err := client.UpdateActionReport(ctx, &report); err != nil { | ||
return err | ||
} | ||
|
||
return client.Commit() | ||
} |