-
Notifications
You must be signed in to change notification settings - Fork 6
/
handler.go
151 lines (126 loc) · 4.04 KB
/
handler.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package course
import (
"context"
"errors"
"fmt"
"net/http"
"time"
"github.com/jmoiron/sqlx"
"github.com/polldo/govod/api/web"
"github.com/polldo/govod/api/weberr"
"github.com/polldo/govod/core/claims"
"github.com/polldo/govod/database"
"github.com/polldo/govod/validate"
)
// HandleCreate allows administrators to add new courses.
func HandleCreate(db *sqlx.DB) web.Handler {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
var c CourseNew
if err := web.Decode(w, r, &c); err != nil {
return weberr.BadRequest(fmt.Errorf("unable to decode payload: %w", err))
}
if err := validate.Check(c); err != nil {
return weberr.NewError(err, err.Error(), http.StatusUnprocessableEntity)
}
now := time.Now().UTC()
course := Course{
ID: validate.GenerateID(),
Name: c.Name,
Description: c.Description,
Price: c.Price,
ImageURL: c.ImageURL,
CreatedAt: now,
UpdatedAt: now,
}
if err := Create(ctx, db, course); err != nil {
if errors.Is(err, database.ErrDBDuplicatedEntry) {
return weberr.NewError(err, "passed course already exists", http.StatusUnprocessableEntity)
}
return err
}
return web.Respond(ctx, w, course, http.StatusCreated)
}
}
// HandleUpdate allows administrators to update existing courses.
func HandleUpdate(db *sqlx.DB) web.Handler {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
courseID := web.Param(r, "id")
if err := validate.CheckID(courseID); err != nil {
return weberr.NewError(err, err.Error(), http.StatusUnprocessableEntity)
}
var cup CourseUp
if err := web.Decode(w, r, &cup); err != nil {
return weberr.BadRequest(fmt.Errorf("unable to decode payload: %w", err))
}
if err := validate.Check(cup); err != nil {
return weberr.NewError(err, err.Error(), http.StatusUnprocessableEntity)
}
course, err := Fetch(ctx, db, courseID)
if err != nil {
err := fmt.Errorf("fetching passed course[%s]: %w", courseID, err)
if errors.Is(err, database.ErrDBNotFound) {
return weberr.NotFound(err)
}
return err
}
if cup.Name != nil {
course.Name = *cup.Name
}
if cup.Description != nil {
course.Description = *cup.Description
}
if cup.Price != nil {
course.Price = *cup.Price
}
if cup.ImageURL != nil {
course.ImageURL = *cup.ImageURL
}
course.UpdatedAt = time.Now().UTC()
if course, err = Update(ctx, db, course); err != nil {
return fmt.Errorf("updating course[%s]: %w", course.ID, err)
}
return web.Respond(ctx, w, course, http.StatusOK)
}
}
// HandleList allows users to fetch all available courses.
func HandleList(db *sqlx.DB) web.Handler {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
courses, err := FetchAll(ctx, db)
if err != nil {
return fmt.Errorf("fetching all courses: %w", err)
}
return web.Respond(ctx, w, courses, http.StatusOK)
}
}
// HandleList allows users to fetch courses they own.
func HandleListOwned(db *sqlx.DB) web.Handler {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
clm, err := claims.Get(ctx)
if err != nil {
return weberr.NotAuthorized(errors.New("user not authenticated"))
}
courses, err := FetchByOwner(ctx, db, clm.UserID)
if err != nil {
return fmt.Errorf("fetching courses of user[%s]: %w", clm.UserID, err)
}
return web.Respond(ctx, w, courses, http.StatusOK)
}
}
// HandleShow allows users to fetch the information of a specific course.
func HandleShow(db *sqlx.DB) web.Handler {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
courseID := web.Param(r, "id")
if err := validate.CheckID(courseID); err != nil {
return weberr.NewError(err, err.Error(), http.StatusUnprocessableEntity)
}
course, err := Fetch(ctx, db, courseID)
if err != nil {
err := fmt.Errorf("fetching course[%s]: %w", courseID, err)
if errors.Is(err, database.ErrDBNotFound) {
return weberr.NotFound(err)
}
return err
}
return web.Respond(ctx, w, course, http.StatusOK)
}
}