Skip to content

Commit e7504d8

Browse files
committed
fix totem API issues
1 parent 0a2bbf2 commit e7504d8

File tree

5 files changed

+182
-63
lines changed

5 files changed

+182
-63
lines changed

src/dao/totem.go

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import (
66
"context"
77
"database/sql"
88
"errors"
9+
"strings"
910
"time"
1011
)
1112

1213
var (
13-
ErrTotemNotFound = errors.New("totem not found")
14+
ErrTotemNotFound = errors.New("totem not found")
15+
ErrTotemAlreadyExists = errors.New("totem already exists")
1416
)
1517

1618
type TotemDao struct {
@@ -23,7 +25,7 @@ func NewTotemDao() *TotemDao {
2325
}
2426
}
2527

26-
func (td *TotemDao) GetTotemById(ctx context.Context, id int64) (error, api.TotemResponse) {
28+
func (td *TotemDao) GetTotemById(ctx context.Context, id string) (error, api.TotemResponse) {
2729
query := `
2830
SELECT id, zone_id, latitude, longitude, registration_time
2931
FROM totems
@@ -68,5 +70,69 @@ func (td *TotemDao) AddTotem(ctx context.Context, config api.TotemRequest) error
6870
config.Longitude,
6971
)
7072

73+
if err != nil {
74+
if strings.Contains(err.Error(), "duplicate key value violates unique constraint") {
75+
return ErrTotemAlreadyExists
76+
}
77+
}
7178
return err
7279
}
80+
81+
func (td *TotemDao) GetTotems(ctx context.Context, limit int, offset int) ([]api.TotemResponse, error) {
82+
query := `
83+
SELECT id, zone_id, latitude, longitude, registration_time
84+
FROM totems
85+
LIMIT $1 OFFSET $2
86+
`
87+
88+
rows, err := td.db.Query(ctx, query, limit, offset)
89+
if err != nil {
90+
return nil, err
91+
}
92+
defer rows.Close()
93+
94+
var totems []api.TotemResponse
95+
96+
for rows.Next() {
97+
var totem api.TotemResponse
98+
var registrationTime time.Time
99+
100+
if err := rows.Scan(
101+
&totem.Id,
102+
&totem.ZoneId,
103+
&totem.Latitude,
104+
&totem.Longitude,
105+
&registrationTime,
106+
); err != nil {
107+
return nil, err
108+
}
109+
110+
totem.RegistrationTime = registrationTime
111+
totems = append(totems, totem)
112+
}
113+
114+
if err := rows.Err(); err != nil {
115+
return nil, err
116+
}
117+
118+
return totems, nil
119+
}
120+
121+
func (td *TotemDao) DeleteTotemById(ctx context.Context, id string) error {
122+
query := `
123+
DELETE FROM totems
124+
WHERE id = $1
125+
`
126+
127+
result, err := td.db.Exec(ctx, query, id)
128+
if err != nil {
129+
return err
130+
}
131+
132+
rowsAffected := result.RowsAffected()
133+
if rowsAffected == 0 {
134+
return ErrTotemNotFound
135+
}
136+
137+
return nil
138+
}

src/handlers/fine.go

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,22 @@ func (fh *FineHandlers) GetCarFines(c *gin.Context, plate string) {
4848
c.JSON(http.StatusOK, fines)
4949
}
5050

51+
func (fh *FineHandlers) GetZoneFines(c *gin.Context, zoneId int64, params api.GetZoneFinesParams) {
52+
username, role, err := auth.GetPermissions(c)
53+
if err != nil {
54+
return
55+
}
56+
zh := NewZoneHandler()
57+
isAdmin, errAdmin := zh.isZoneAdmin(c, zoneId, username)
58+
isController, errController := zh.isZoneController(c, zoneId, username)
59+
if role != "superuser" && !isAdmin && !isController && errAdmin != nil && errController != nil {
60+
return
61+
}
62+
63+
fines := fh.dao.GetZoneFines(c.Request.Context(), zoneId, *params.Limit, *params.Offset)
64+
c.JSON(http.StatusOK, fines)
65+
}
66+
5167
func (fh *FineHandlers) CreateZoneFine(c *gin.Context, zoneId int64) {
5268
username, role, err := auth.GetPermissions(c)
5369
if err != nil {
@@ -56,7 +72,7 @@ func (fh *FineHandlers) CreateZoneFine(c *gin.Context, zoneId int64) {
5672
zh := NewZoneHandler()
5773
isAdmin, errAdmin := zh.isZoneAdmin(c, zoneId, username)
5874
isController, errController := zh.isZoneController(c, zoneId, username)
59-
if role != "superuser" || !isAdmin || !isController || errAdmin != nil || errController != nil {
75+
if role != "superuser" && !isAdmin && !isController && errAdmin != nil && errController != nil {
6076
return
6177
}
6278

@@ -172,19 +188,3 @@ func (fh *FineHandlers) PayFine(c *gin.Context, id int64) {
172188

173189
c.JSON(http.StatusOK, gin.H{"message": "fine paid successfully"})
174190
}
175-
176-
func (fh *FineHandlers) GetZoneFines(c *gin.Context, zoneId int64, params api.GetZoneFinesParams) {
177-
username, role, err := auth.GetPermissions(c)
178-
if err != nil {
179-
return
180-
}
181-
zh := NewZoneHandler()
182-
isAdmin, errAdmin := zh.isZoneAdmin(c, zoneId, username)
183-
isController, errController := zh.isZoneController(c, zoneId, username)
184-
if role != "superuser" || !isAdmin || !isController || errAdmin != nil || errController != nil {
185-
return
186-
}
187-
188-
fines := fh.dao.GetZoneFines(c.Request.Context(), zoneId, *params.Limit, *params.Offset)
189-
c.JSON(http.StatusOK, fines)
190-
}

src/handlers/ticket.go

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,38 @@ func (th *TicketHandlers) GetTicketById(c *gin.Context, id int64) {
7979
c.JSON(http.StatusOK, ticket)
8080
}
8181

82+
func (fh *FineHandlers) GetZoneTickets(c *gin.Context, zoneId int64, params api.GetZoneTicketsParams) {
83+
username, role, err := auth.GetPermissions(c)
84+
if err != nil {
85+
return
86+
}
87+
zh := NewZoneHandler()
88+
isAdmin, errAdmin := zh.isZoneAdmin(c, zoneId, username)
89+
isController, errController := zh.isZoneController(c, zoneId, username)
90+
91+
if role != "superuser" && (errAdmin != nil || !isAdmin) && (errController != nil || !isController) {
92+
c.JSON(http.StatusForbidden, gin.H{"error": "forbidden"})
93+
return
94+
}
95+
96+
tickets, err := fh.dao.GetZoneTickets(c.Request.Context(), zoneId, *params.Limit, *params.Offset)
97+
if err != nil {
98+
if errors.Is(err, dao.ErrZoneNotFound) {
99+
c.JSON(http.StatusNotFound, gin.H{"error": "zone not found"})
100+
return
101+
}
102+
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get zone tickets"})
103+
return
104+
}
105+
106+
if tickets == nil {
107+
c.JSON(http.StatusOK, []interface{}{})
108+
return
109+
}
110+
111+
c.JSON(http.StatusOK, tickets)
112+
}
113+
82114
func (th *TicketHandlers) CreateZoneTicket(c *gin.Context, zoneId int64) {
83115
var ticketRequest api.TicketRequest
84116
if err := c.ShouldBindJSON(&ticketRequest); err != nil {
@@ -197,35 +229,3 @@ func (th *TicketHandlers) DeleteTicketById(c *gin.Context, id int64) {
197229

198230
c.JSON(http.StatusOK, gin.H{"message": "ticket deleted successfully"})
199231
}
200-
201-
func (fh *FineHandlers) GetZoneTickets(c *gin.Context, zoneId int64, params api.GetZoneTicketsParams) {
202-
username, role, err := auth.GetPermissions(c)
203-
if err != nil {
204-
return
205-
}
206-
zh := NewZoneHandler()
207-
isAdmin, errAdmin := zh.isZoneAdmin(c, zoneId, username)
208-
isController, errController := zh.isZoneController(c, zoneId, username)
209-
210-
if role != "superuser" && (errAdmin != nil || !isAdmin) && (errController != nil || !isController) {
211-
c.JSON(http.StatusForbidden, gin.H{"error": "forbidden"})
212-
return
213-
}
214-
215-
tickets, err := fh.dao.GetZoneTickets(c.Request.Context(), zoneId, *params.Limit, *params.Offset)
216-
if err != nil {
217-
if errors.Is(err, dao.ErrZoneNotFound) {
218-
c.JSON(http.StatusNotFound, gin.H{"error": "zone not found"})
219-
return
220-
}
221-
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get zone tickets"})
222-
return
223-
}
224-
225-
if tickets == nil {
226-
c.JSON(http.StatusOK, []interface{}{})
227-
return
228-
}
229-
230-
c.JSON(http.StatusOK, tickets)
231-
}

src/handlers/totem.go

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"OPP/backend/auth"
66
"OPP/backend/dao"
77
"net/http"
8-
"strconv"
98

109
"github.com/gin-gonic/gin"
1110
)
@@ -20,12 +19,7 @@ func NewTotemHandler() *TotemHandlers {
2019
}
2120
}
2221

23-
func (th *TotemHandlers) GetTotemConfig(c *gin.Context, params api.GetTotemConfigParams) {
24-
id, err := strconv.ParseInt(params.Id, 10, 64)
25-
if err != nil || id <= 0 {
26-
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid totem ID"})
27-
return
28-
}
22+
func (th *TotemHandlers) GetTotemConfig(c *gin.Context, id string) {
2923
err, totemConfig := th.dao.GetTotemById(c.Request.Context(), id)
3024
if err != nil {
3125
if err == dao.ErrTotemNotFound {
@@ -51,9 +45,68 @@ func (th *TotemHandlers) RegisterTotem(c *gin.Context) {
5145
return
5246
}
5347

48+
// Check if zone exists
49+
_, err := dao.NewZoneDao().GetZoneById(c.Request.Context(), totemRequest.ZoneId)
50+
if err != nil {
51+
if err == dao.ErrZoneNotFound {
52+
c.JSON(http.StatusNotFound, gin.H{"error": "zone not found"})
53+
return
54+
}
55+
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to check if zone exists"})
56+
return
57+
}
58+
5459
if err := th.dao.AddTotem(c.Request.Context(), totemRequest); err != nil {
60+
if err == dao.ErrTotemAlreadyExists {
61+
c.JSON(http.StatusConflict, gin.H{"error": "totem already exists"})
62+
return
63+
}
5564
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to register totem"})
5665
return
5766
}
5867
c.JSON(http.StatusOK, gin.H{"message": "totem registered successfully"})
5968
}
69+
70+
func (th *TotemHandlers) GetAllTotems(c *gin.Context, params api.GetAllTotemsParams) {
71+
totems, err := th.dao.GetTotems(c.Request.Context(), *params.Limit, *params.Offset)
72+
if err != nil {
73+
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get totems"})
74+
return
75+
}
76+
c.JSON(http.StatusOK, totems)
77+
}
78+
79+
func (th *TotemHandlers) DeleteTotemById(c *gin.Context, id string) {
80+
username, role, err := auth.GetPermissions(c)
81+
if err != nil {
82+
return
83+
}
84+
85+
// Get totem by ID
86+
err, totem := th.dao.GetTotemById(c.Request.Context(), id)
87+
if err != nil {
88+
if err == dao.ErrTotemNotFound {
89+
c.JSON(http.StatusNotFound, gin.H{"error": "totem not found"})
90+
return
91+
}
92+
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get totem"})
93+
return
94+
}
95+
isZoneAdmin, err := NewZoneHandler().isZoneAdmin(c, totem.ZoneId, username)
96+
97+
if role != "superuser" && !isZoneAdmin {
98+
c.JSON(http.StatusForbidden, gin.H{"forbidden": "you do not have permission to delete this totem"})
99+
return
100+
}
101+
102+
err = th.dao.DeleteTotemById(c.Request.Context(), id)
103+
if err != nil {
104+
if err == dao.ErrTotemNotFound {
105+
c.JSON(http.StatusNotFound, gin.H{"error": "totem not found"})
106+
return
107+
}
108+
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete totem"})
109+
return
110+
}
111+
c.JSON(http.StatusOK, gin.H{"message": "totem deleted successfully"})
112+
}

src/handlers/zone.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ func (zh *ZoneHandlers) UpdateZoneById(c *gin.Context, id int64) {
126126
return
127127
}
128128
isAdmin, err := zh.isZoneAdmin(c, id, username)
129-
if role != "admin" || !isAdmin || err != nil {
129+
if role != "superuser" && (!isAdmin || err != nil) {
130130
return
131131
}
132132

@@ -159,7 +159,7 @@ func (zh *ZoneHandlers) DeleteZoneById(c *gin.Context, id int64) {
159159
return
160160
}
161161
isAdmin, err := zh.isZoneAdmin(c, id, username)
162-
if role != "superuser" || !isAdmin || err != nil {
162+
if role != "superuser" && (!isAdmin || err != nil) {
163163
return
164164
}
165165

@@ -207,7 +207,7 @@ func (zh *ZoneHandlers) GetZoneUsers(c *gin.Context, id int64) {
207207
}
208208

209209
isAdmin, err := zh.isZoneAdmin(c, id, username)
210-
if role != "superuser" || !isAdmin || err != nil {
210+
if role != "superuser" && (!isAdmin || err != nil) {
211211
return
212212
}
213213

@@ -260,7 +260,7 @@ func (zh *ZoneHandlers) AddZoneUserRole(c *gin.Context, id int64) {
260260
}
261261
} else if request.Role == "controller" {
262262
isAdmin, err := zh.isZoneAdmin(c, id, username)
263-
if role != "superuser" && (!isAdmin || err != nil) || err != nil {
263+
if role != "superuser" && (!isAdmin || err != nil) {
264264
return
265265
}
266266
}
@@ -288,7 +288,7 @@ func (zh *ZoneHandlers) RemoveZoneUserRole(c *gin.Context, id int64, username st
288288
return
289289
}
290290
isAdmin, err := zh.isZoneAdmin(c, id, username)
291-
if role != "superuser" || !isAdmin || err != nil {
291+
if role != "superuser" && (!isAdmin || err != nil) {
292292
return
293293
}
294294

0 commit comments

Comments
 (0)