Passed
Pull Request — main (#42)
by Yume
01:11
created

controllers.DeleteCardByID   B

Complexity

Conditions 5

Size

Total Lines 43
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 28
nop 1
dl 0
loc 43
rs 8.7413
c 0
b 0
f 0
1
package controllers
2
3
import (
4
	"fmt"
5
	"github.com/gofiber/fiber/v2"
6
	"github.com/memnix/memnixrest/app/models"
7
	"github.com/memnix/memnixrest/app/queries"
8
	"github.com/memnix/memnixrest/pkg/core"
9
	"github.com/memnix/memnixrest/pkg/database"
10
	"github.com/memnix/memnixrest/pkg/utils"
11
	"net/http"
12
	"strconv"
13
)
14
15
// GetAllTodayCard function to get all today card for a user
16
// @Description Get all today card
17
// @Summary gets a list of card
18
// @Tags Card
19
// @Produce json
20
// @Success 200  {array} models.TodayResponse
21
// @Security Beaver
22
// @Router /v1/cards/today [get]
23
func GetAllTodayCard(c *fiber.Ctx) error {
24
	var res *models.ResponseHTTP
25
26
	auth := CheckAuth(c, models.PermUser) // Check auth
27
	if !auth.Success {
28
		return queries.AuthError(c, &auth)
29
	}
30
31
	if res = queries.FetchTodayCard(auth.User.ID); !res.Success {
32
		log := models.CreateLog(fmt.Sprintf("Error on GetAllTodayCard: %s", res.Message), models.LogQueryGetError).SetType(models.LogTypeError).AttachIDs(auth.User.ID, 0, 0)
33
		_ = log.SendLog()
34
		return queries.RequestError(c, http.StatusInternalServerError, res.Message)
35
	}
36
37
	return c.Status(http.StatusOK).JSON(models.ResponseHTTP{
38
		Success: true,
39
		Message: "Get today's cards",
40
		Data:    res.Data,
41
		Count:   res.Count,
42
	})
43
}
44
45
// GetTrainingCardsByDeck function to get training cards by deck
46
// @Description Get training cards from a deck
47
// @Summary gets a list of cards
48
// @Tags Card
49
// @Produce json
50
// @Success 200 {array} models.Card
51
// @Param deckId path int true "Deck ID"
52
// @Security Beaver
53
// @Router /v1/cards/{deckID}/training [get]
54
func GetTrainingCardsByDeck(c *fiber.Ctx) error {
55
	res := new(models.ResponseHTTP)
56
57
	auth := CheckAuth(c, models.PermUser) // Check auth
58
	if !auth.Success {
59
		return queries.AuthError(c, &auth)
60
	}
61
62
	deckID := c.Params("deckID")
63
	deckIDInt, _ := strconv.ParseInt(deckID, 10, 32)
64
65
	access := queries.CheckAccess(auth.User.ID, uint(deckIDInt), models.AccessStudent)
66
	if !access.Success {
67
		log := models.CreateLog(fmt.Sprintf("Forbidden from %s on deck %d - GetTodayCard: %s", auth.User.Email, deckIDInt, res.Message), models.LogPermissionForbidden).SetType(models.LogTypeWarning).AttachIDs(auth.User.ID, uint(deckIDInt), 0)
68
		_ = log.SendLog()
69
		return queries.RequestError(c, http.StatusForbidden, utils.ErrorForbidden)
70
	}
71
72
	if res = queries.FetchTrainingCards(auth.User.ID, uint(deckIDInt)); !res.Success {
73
		log := models.CreateLog(fmt.Sprintf("Error on GetTrainingCardsByDeck: %s from %s", res.Message, auth.User.Email), models.LogQueryGetError).SetType(models.LogTypeError).AttachIDs(auth.User.ID, uint(deckIDInt), 0)
74
		_ = log.SendLog()
75
		return queries.RequestError(c, http.StatusInternalServerError, res.Message)
76
	}
77
78
	return c.Status(http.StatusOK).JSON(models.ResponseHTTP{
79
		Success: true,
80
		Message: "Get today's card",
81
		Data:    res.Data,
82
		Count:   res.Count,
83
	})
84
}
85
86
// GetAllCards function to get all cards (deprecated)
87
// @Description Get every card. Shouldn't really be used
88
// @Summary gets all cards
89
// @Tags Card
90
// @Produce json
91
// @Security Admin
92
// @Success 200 {array} models.Card
93
// @Router /v1/cards/ [get]
94
// @Deprecated
95
func GetAllCards(c *fiber.Ctx) error {
96
	db := database.DBConn // DB Conn
97
98
	auth := CheckAuth(c, models.PermAdmin) // Check auth
99
	if !auth.Success {
100
		return queries.AuthError(c, &auth)
101
	}
102
103
	var cards []models.Card
104
105
	if res := db.Joins("Deck").Find(&cards); res.Error != nil {
106
		return queries.RequestError(c, http.StatusInternalServerError, utils.ErrorRequestFailed)
107
	}
108
	return c.Status(http.StatusOK).JSON(models.ResponseHTTP{
109
		Success: true,
110
		Message: "Get All cards",
111
		Data:    cards,
112
		Count:   len(cards),
113
	})
114
}
115
116
// GetCardByID function to get a card by id
117
// @Description Get a card by id
118
// @Summary gets a card
119
// @Tags Card
120
// @Produce json
121
// @Param id path int true "Card ID"
122
// @Security Admin
123
// @Success 200 {object} models.Card
124
// @Router /v1/cards/id/{id} [get]
125
func GetCardByID(c *fiber.Ctx) error {
126
	db := database.DBConn // DB Conn
127
128
	auth := CheckAuth(c, models.PermAdmin) // Check auth
129
	if !auth.Success {
130
		return queries.AuthError(c, &auth)
131
	}
132
	// Params
133
	id := c.Params("id")
134
135
	card := new(models.Card)
136
137
	if err := db.Joins("Deck").Joins("Mcq").First(&card, id).Error; err != nil {
138
		return queries.RequestError(c, http.StatusInternalServerError, err.Error())
139
	}
140
141
	return c.Status(http.StatusOK).JSON(models.ResponseHTTP{
142
		Success: true,
143
		Message: "Success get card by ID.",
144
		Data:    *card,
145
		Count:   1,
146
	})
147
}
148
149
// GetCardsFromDeck method to get cards from deck
150
// @Description Get every card from a deck
151
// @Summary gets a list of card
152
// @Tags Card
153
// @Produce json
154
// @Param deckID path int true "Deck ID"
155
// @Security Beaver
156
// @Success 200 {array} models.Card
157
// @Router /v1/cards/deck/{deckID} [get]
158
func GetCardsFromDeck(c *fiber.Ctx) error {
159
	db := database.DBConn // DB Conn
160
161
	// Params
162
	id := c.Params("deckID")
163
	deckID, _ := strconv.ParseUint(id, 10, 32)
164
165
	auth := CheckAuth(c, models.PermUser) // Check auth
166
	if !auth.Success {
167
		return queries.AuthError(c, &auth)
168
	}
169
170
	if res := queries.CheckAccess(auth.User.ID, uint(deckID), models.AccessStudent); !res.Success {
171
		log := models.CreateLog(fmt.Sprintf("Forbidden from %s on deck %d - GetCardsFromDeck: %s", auth.User.Email, deckID, res.Message), models.LogPermissionForbidden).SetType(models.LogTypeWarning).AttachIDs(auth.User.ID, uint(deckID), 0)
172
		_ = log.SendLog()
173
		return queries.RequestError(c, http.StatusForbidden, utils.ErrorForbidden)
174
	}
175
176
	var cards []models.Card
177
178
	if err := db.Joins("Deck").Joins("Mcq").Where("cards.deck_id = ?", id).Find(&cards).Error; err != nil {
179
		log := models.CreateLog(fmt.Sprintf("Error on GetCardsFromDeck: %s from %s on %d", err.Error(), auth.User.Email, deckID), models.LogQueryGetError).SetType(models.LogTypeError).AttachIDs(auth.User.ID, uint(deckID), 0)
180
		_ = log.SendLog()
181
		return queries.RequestError(c, http.StatusInternalServerError, err.Error())
182
	}
183
184
	return c.Status(http.StatusOK).JSON(models.ResponseHTTP{
185
		Success: true,
186
		Message: "Success get cards from deck.",
187
		Data:    cards,
188
		Count:   len(cards),
189
	})
190
}
191
192
// POST
193
194
// CreateNewCard method
195
// @Description Create a new card (must be a deck editor)
196
// @Summary creates a card
197
// @Tags Card
198
// @Produce json
199
// @Accept json
200
// @Security Beaver
201
// @Param card body models.Card true "Card to create"
202
// @Success 200
203
// @Router /v1/cards/new [post]
204
func CreateNewCard(c *fiber.Ctx) error {
205
	db := database.DBConn // DB Conn
206
	card := new(models.Card)
207
208
	auth := CheckAuth(c, models.PermUser) // Check auth
209
	if !auth.Success {
210
		return queries.AuthError(c, &auth)
211
	}
212
213
	if err := c.BodyParser(&card); err != nil {
214
		log := models.CreateLog(fmt.Sprintf("Error on CreateNewCard: %s from %s", err.Error(), auth.User.Email), models.LogBodyParserError).SetType(models.LogTypeError).AttachIDs(auth.User.ID, 0, 0)
215
		_ = log.SendLog()
216
		return queries.RequestError(c, http.StatusBadRequest, err.Error())
217
	}
218
219
	if res := queries.CheckAccess(auth.User.ID, card.DeckID, models.AccessEditor); !res.Success {
220
		log := models.CreateLog(fmt.Sprintf("Forbidden from %s on deck %d - CreateNewCard: %s", auth.User.Email, card.DeckID, res.Message), models.LogPermissionForbidden).SetType(models.LogTypeWarning).AttachIDs(auth.User.ID, card.DeckID, 0)
221
		_ = log.SendLog()
222
		return queries.RequestError(c, http.StatusForbidden, utils.ErrorForbidden)
223
	}
224
225
	if res := queries.CheckCardLimit(auth.User.Permissions, card.DeckID); !res {
226
		log := models.CreateLog(fmt.Sprintf("Forbidden from %s on deck %d - CreateNewCard: This deck has reached his limit", auth.User.Email, card.DeckID), models.LogDeckCardLimit).SetType(models.LogTypeWarning).AttachIDs(auth.User.ID, card.DeckID, 0)
227
		_ = log.SendLog()
228
		return queries.RequestError(c, http.StatusForbidden, "This deck has reached his limit ! You can't add more card to it.")
229
	}
230
231
	if card.NotValidate() {
232
		log := models.CreateLog(fmt.Sprintf("BadRequest from %s on deck %d - CreateNewCard: BadRequest", auth.User.Email, card.DeckID), models.LogBadRequest).SetType(models.LogTypeWarning).AttachIDs(auth.User.ID, card.DeckID, 0)
233
		_ = log.SendLog()
234
		return queries.RequestError(c, http.StatusBadRequest, utils.ErrorQALen)
235
	}
236
237
	_, ok := card.ValidateMCQ(&auth.User)
238
	if !ok {
239
		return queries.RequestError(c, http.StatusInternalServerError, utils.ErrorRequestFailed)
240
	}
241
242
	db.Create(card)
243
244
	log := models.CreateLog(fmt.Sprintf("Created: %d - %s", card.ID, card.Question), models.LogCardCreated).SetType(models.LogTypeInfo).AttachIDs(auth.User.ID, card.DeckID, card.ID)
245
	_ = log.SendLog()
246
247
	if res := queries.UpdateSubUsers(card, &auth.User); res != nil {
248
		return queries.RequestError(c, http.StatusInternalServerError, utils.ErrorRequestFailed)
249
	}
250
251
	return c.Status(http.StatusOK).JSON(models.ResponseHTTP{
252
		Success: true,
253
		Message: "Success register a card",
254
		Data:    *card,
255
		Count:   1,
256
	})
257
}
258
259
// PostSelfEvaluateResponse method
260
// @Description Post a self evaluated response
261
// @Summary posts a response
262
// @Tags Card
263
// @Produce json
264
// @Security Beaver
265
// @Accept json
266
// @Param card body models.CardSelfResponse true "Self response"
267
// @Success 200
268
// @Router /v1/cards/selfresponse [post]
269
func PostSelfEvaluateResponse(c *fiber.Ctx) error {
270
	db := database.DBConn // DB Conn
271
272
	auth := CheckAuth(c, models.PermUser) // Check auth
273
	if !auth.Success {
274
		return queries.AuthError(c, &auth)
275
	}
276
277
	response := new(models.CardSelfResponse)
278
	card := new(models.Card)
279
280
	if err := c.BodyParser(&response); err != nil {
281
		log := models.CreateLog(fmt.Sprintf("Error on PostSelfEvaluateResponse: %s from %s", err.Error(), auth.User.Email), models.LogBodyParserError).SetType(models.LogTypeError).AttachIDs(auth.User.ID, 0, 0)
282
		_ = log.SendLog()
283
		return queries.RequestError(c, http.StatusBadRequest, err.Error())
284
	}
285
286
	if response.Quality > 4 || response.Quality < 1 {
287
		log := models.CreateLog(fmt.Sprintf("Error on PostSelfEvaluateResponse: Quality > 4 from %s", auth.User.Email), models.LogBodyParserError).SetType(models.LogTypeError).AttachIDs(auth.User.ID, 0, 0)
288
		_ = log.SendLog()
289
		return queries.RequestError(c, http.StatusBadRequest, utils.ErrorBreak)
290
	}
291
292
	if err := db.Joins("Deck").First(&card, response.CardID).Error; err != nil {
293
		log := models.CreateLog(fmt.Sprintf("Error on PostSelfEvaluateResponse: %s from %s", err.Error(), auth.User.Email), models.LogQueryGetError).SetType(models.LogTypeError).AttachIDs(auth.User.ID, 0, 0)
294
		_ = log.SendLog()
295
		return queries.RequestError(c, http.StatusServiceUnavailable, err.Error())
296
	}
297
298
	res := queries.CheckAccess(auth.User.ID, card.Deck.ID, models.AccessStudent)
299
	if !res.Success {
300
		log := models.CreateLog(fmt.Sprintf("Forbidden from %s on deck %d - PostSelfEvaluateResponse: %s", auth.User.Email, card.DeckID, res.Message), models.LogPermissionForbidden).SetType(models.LogTypeWarning).AttachIDs(auth.User.ID, card.DeckID, 0)
301
		_ = log.SendLog()
302
		return queries.RequestError(c, http.StatusForbidden, utils.ErrorForbidden)
303
	}
304
305
	//TODO: Add error handling
306
	_ = queries.PostSelfEvaluatedMem(&auth.User, card, response.Quality, response.Training)
307
308
	return c.Status(http.StatusOK).JSON(models.ResponseHTTP{
309
		Success: true,
310
		Message: "Success post response",
311
		Data:    nil,
312
		Count:   1,
313
	})
314
}
315
316
// PostResponse method
317
// @Description Post a response and check it
318
// @Summary posts a response
319
// @Tags Card
320
// @Produce json
321
// @Security Beaver
322
// @Accept json
323
// @Param card body models.CardResponse true "Response"
324
// @Success 200 {object} models.CardResponseValidation
325
// @Router /v1/cards/response [post]
326
func PostResponse(c *fiber.Ctx) error {
327
	db := database.DBConn // DB Conn
328
329
	auth := CheckAuth(c, models.PermUser) // Check auth
330
	if !auth.Success {
331
		return queries.AuthError(c, &auth)
332
	}
333
334
	response := new(models.CardResponse)
335
	card := new(models.Card)
336
337
	if err := c.BodyParser(&response); err != nil {
338
		log := models.CreateLog(fmt.Sprintf("Error on PostResponse: %s from %s", err.Error(), auth.User.Email), models.LogBodyParserError).SetType(models.LogTypeError).AttachIDs(auth.User.ID, 0, 0)
339
		_ = log.SendLog()
340
		return queries.RequestError(c, http.StatusBadRequest, err.Error())
341
	}
342
343
	if err := db.Joins("Deck").First(&card, response.CardID).Error; err != nil {
344
		log := models.CreateLog(fmt.Sprintf("Error on PostResponse: %s from %s", err.Error(), auth.User.Email), models.LogQueryGetError).SetType(models.LogTypeError).AttachIDs(auth.User.ID, 0, 0)
345
		_ = log.SendLog()
346
		return queries.RequestError(c, http.StatusServiceUnavailable, err.Error())
347
	}
348
349
	res := queries.CheckAccess(auth.User.ID, card.Deck.ID, models.AccessStudent)
350
	if !res.Success {
351
		log := models.CreateLog(fmt.Sprintf("Forbidden from %s on deck %d - PostResponse: %s", auth.User.Email, card.DeckID, res.Message), models.LogPermissionForbidden).SetType(models.LogTypeWarning).AttachIDs(auth.User.ID, card.DeckID, 0)
352
		_ = log.SendLog()
353
		return queries.RequestError(c, http.StatusForbidden, utils.ErrorForbidden)
354
	}
355
356
	validation := new(models.CardResponseValidation)
357
358
	if core.ValidateAnswer(response.Response, card) {
359
		validation.SetCorrect()
360
	} else {
361
		validation.SetIncorrect()
362
	}
363
364
	//TODO: Add error handling
365
	_ = queries.PostMem(&auth.User, card, validation, response.Training)
366
367
	validation.Answer = card.Answer
368
369
	return c.Status(http.StatusOK).JSON(models.ResponseHTTP{
370
		Success: true,
371
		Message: "Success post response",
372
		Data:    *validation,
373
		Count:   1,
374
	})
375
}
376
377
// PUT
378
379
// UpdateCardByID method
380
// @Description Edit a card
381
// @Summary edits a card
382
// @Tags Card
383
// @Produce json
384
// @Success 200 {object} models.Card
385
// @Security Beaver
386
// @Accept json
387
// @Param card body models.Card true "card to edit"
388
// @Param id path int true "card id"
389
// @Router /v1/cards/{cardID}/edit [put]
390
func UpdateCardByID(c *fiber.Ctx) error {
391
	db := database.DBConn // DB Conn
392
393
	// Params
394
	id := c.Params("id")
395
	cardID, _ := strconv.ParseUint(id, 10, 32)
396
397
	auth := CheckAuth(c, models.PermUser) // Check auth
398
	if !auth.Success {
399
		return queries.AuthError(c, &auth)
400
	}
401
402
	card := new(models.Card)
403
404
	if err := db.First(&card, id).Error; err != nil {
405
		log := models.CreateLog(fmt.Sprintf("Error on UpdateCardByID: %s from %s", err.Error(), auth.User.Email), models.LogQueryGetError).SetType(models.LogTypeError).AttachIDs(auth.User.ID, 0, uint(cardID))
406
		_ = log.SendLog()
407
		return queries.RequestError(c, http.StatusInternalServerError, err.Error())
408
	}
409
410
	if res := queries.CheckAccess(auth.User.ID, card.DeckID, models.AccessEditor); !res.Success {
411
		log := models.CreateLog(fmt.Sprintf("Forbidden from %s on deck %d - UpdateCardByID: %s", auth.User.Email, card.DeckID, res.Message), models.LogPermissionForbidden).SetType(models.LogTypeWarning).AttachIDs(auth.User.ID, card.DeckID, uint(cardID))
412
		_ = log.SendLog()
413
		return queries.RequestError(c, http.StatusForbidden, utils.ErrorForbidden)
414
	}
415
416
	if err := UpdateCard(c, card, &auth.User); !err.Success {
417
		log := models.CreateLog(fmt.Sprintf("Error on UpdateCardByID: %s from %s", err.Message, auth.User.Email), models.LogBadRequest).SetType(models.LogTypeError).AttachIDs(auth.User.ID, 0, uint(cardID))
418
		_ = log.SendLog()
419
		return queries.RequestError(c, http.StatusBadRequest, err.Message)
420
	}
421
422
	log := models.CreateLog(fmt.Sprintf("Edited: %d - %s", card.ID, card.Question), models.LogCardEdited).SetType(models.LogTypeInfo).AttachIDs(auth.User.ID, card.DeckID, card.ID)
423
	_ = log.SendLog()
424
425
	return c.Status(http.StatusOK).JSON(models.ResponseHTTP{
426
		Success: true,
427
		Message: "Success update card by ID",
428
		Data:    *card,
429
		Count:   1,
430
	})
431
}
432
433
// UpdateCard function
434
func UpdateCard(c *fiber.Ctx, card *models.Card, user *models.User) *models.ResponseHTTP {
435
	db := database.DBConn
436
437
	deckID := card.DeckID
438
439
	res := new(models.ResponseHTTP)
440
441
	if err := c.BodyParser(&card); err != nil {
442
		res.GenerateError(err.Error())
443
		return res
444
	}
445
446
	if deckID != card.DeckID {
447
		res.GenerateError(utils.ErrorBreak)
448
		return res
449
	}
450
451
	if card.NotValidate() {
452
		res.GenerateError(utils.ErrorQALen)
453
		return res
454
	}
455
456
	shouldUpdateMcq := false
457
458
	mcq, ok := card.ValidateMCQ(user)
459
	if !ok {
460
		res.GenerateError(utils.ErrorRequestFailed)
461
		return res
462
	}
463
464
	shouldUpdateMcq = mcq != nil
465
466
	db.Save(card)
467
468
	if shouldUpdateMcq {
469
		mcq.UpdateLinkedAnswers()
470
	}
471
472
	res.GenerateSuccess("Success update card", nil, 0)
473
	return res
474
}
475
476
// DeleteCardByID method
477
// @Description Delete a card (must be a deck owner)
478
// @Summary deletes a card
479
// @Tags Card
480
// @Produce json
481
// @Security Beaver
482
// @Param id path int true "card id"
483
// @Success 200
484
// @Router /v1/cards/{cardID} [delete]
485
func DeleteCardByID(c *fiber.Ctx) error {
486
	db := database.DBConn // DB Conn
487
	id := c.Params("id")
488
	cardID, _ := strconv.ParseUint(id, 10, 32)
489
490
	auth := CheckAuth(c, models.PermUser) // Check auth
491
	if !auth.Success {
492
		return queries.AuthError(c, &auth)
493
	}
494
495
	card := new(models.Card)
496
497
	if err := db.First(&card, id).Error; err != nil {
498
		return queries.RequestError(c, http.StatusServiceUnavailable, err.Error())
499
	}
500
501
	if res := queries.CheckAccess(auth.User.ID, card.DeckID, models.AccessOwner); !res.Success {
502
		log := models.CreateLog(fmt.Sprintf("Forbidden from %s on deck %d - DeleteCardById: %s", auth.User.Email, card.DeckID, res.Message), models.LogPermissionForbidden).SetType(models.LogTypeWarning).AttachIDs(auth.User.ID, card.DeckID, uint(cardID))
503
		_ = log.SendLog()
504
		return queries.RequestError(c, http.StatusForbidden, utils.ErrorForbidden)
505
	}
506
507
	var memDates []models.MemDate
508
509
	if err := db.Joins("Card").Where("mem_dates.card_id = ?", card.ID).Find(&memDates).Error; err != nil {
510
		log := models.CreateLog(fmt.Sprintf("Error on DeleteCardById: %s from %s", err.Error(), auth.User.Email), models.LogQueryGetError).SetType(models.LogTypeError).AttachIDs(auth.User.ID, 0, uint(cardID))
511
		_ = log.SendLog()
512
		return queries.RequestError(c, http.StatusInternalServerError, utils.ErrorRequestFailed)
513
		// TODO: Error
514
	}
515
516
	db.Unscoped().Delete(memDates)
517
518
	db.Delete(card)
519
520
	log := models.CreateLog(fmt.Sprintf("Deleted: %d - %s", card.ID, card.Question), models.LogCardDeleted).SetType(models.LogTypeInfo).AttachIDs(auth.User.ID, card.DeckID, card.ID)
521
	_ = log.SendLog()
522
523
	return c.Status(http.StatusOK).JSON(models.ResponseHTTP{
524
		Success: true,
525
		Message: "Success delete card by ID",
526
		Data:    *card,
527
		Count:   1,
528
	})
529
}
530