Passed
Pull Request — main (#45)
by Yume
01:43
created

controllers.PostSelfEvaluateResponse   B

Complexity

Conditions 7

Size

Total Lines 44
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

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