Passed
Push — main ( 8f130a...e647c7 )
by Yume
02:21
created

queries.FetchNextCardByDeck   B

Complexity

Conditions 7

Size

Total Lines 30
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 21
nop 3
dl 0
loc 30
rs 7.9759
c 0
b 0
f 0
1
package queries
2
3
import (
4
	"errors"
5
	"math/rand"
6
	"memnixrest/app/database"
7
	"memnixrest/app/models"
8
	"memnixrest/pkg/core"
9
	"time"
10
11
	"github.com/gofiber/fiber/v2"
12
	"gorm.io/gorm"
13
)
14
15
func DeleteRating(_ *fiber.Ctx, user *models.User, deck *models.Deck) models.ResponseHTTP {
16
	db := database.DBConn
17
18
	rating := new(models.Rating)
19
20
	if err := db.Where("ratings.user_id = ? AND ratings.deck_id = ?", user.ID, deck.ID).Delete(&rating).Error; err != nil {
21
		return models.ResponseHTTP{
22
			Success: false,
23
			Message: err.Error(),
24
			Data:    nil,
25
			Count:   0,
26
		}
27
	}
28
	return models.ResponseHTTP{
29
		Success: true,
30
		Message: "Rating deleted",
31
		Data:    *rating,
32
		Count:   1,
33
	}
34
}
35
36
func GenerateRating(_ *fiber.Ctx, rating *models.Rating) models.ResponseHTTP {
37
	db := database.DBConn
38
	deck := new(models.Deck)
39
40
	if err := db.First(&deck, rating.DeckID).Error; err != nil {
41
		return models.ResponseHTTP{
42
			Success: false,
43
			Message: "Can't find deck matching the ID provided",
44
			Data:    nil,
45
			Count:   0,
46
		}
47
	}
48
49
	access := new(models.Access)
50
51
	if err := db.Joins("User").Joins("Deck").Where("accesses.user_id = ? AND accesses.deck_id =?", rating.UserID, rating.DeckID).First(&access).Error; err != nil {
52
		return models.ResponseHTTP{
53
			Success: false,
54
			Message: "You don't have the permissions to rate this deck",
55
			Data:    nil,
56
			Count:   0,
57
		}
58
	}
59
60
	if access.Permission < models.AccessStudent {
61
		return models.ResponseHTTP{
62
			Success: false,
63
			Message: "You are not subscribed to this deck",
64
			Data:    nil,
65
			Count:   0,
66
		}
67
	}
68
69
	oldRating := new(models.Rating)
70
71
	if err := db.Joins("User").Joins("Deck").Where("ratings.user_id = ? AND ratings.deck_id = ?", rating.UserID, rating.DeckID).First(&oldRating).Error; err != nil {
72
		if errors.Is(err, gorm.ErrRecordNotFound) {
73
			db.Preload("User").Preload("Deck").Create(rating)
74
			oldRating = rating
75
		}
76
	} else {
77
		oldRating.Value = rating.Value
78
		db.Preload("User").Preload("Deck").Save(oldRating)
79
	}
80
81
	return models.ResponseHTTP{
82
		Success: true,
83
		Message: "Success rate the deck",
84
		Data:    *oldRating,
85
		Count:   1,
86
	}
87
}
88
89
func FillResponseDeck(c *fiber.Ctx, access *models.Access) models.ResponseDeck {
90
	db := database.DBConn
91
92
	deckResponse := new(models.ResponseDeck)
93
94
	deckResponse.Deck = access.Deck
95
	deckResponse.DeckID = access.DeckID
96
	deckResponse.Permission = access.Permission
97
98
	if res := GetDeckOwner(c, access.Deck); res.ID != 0 {
99
		deckResponse.Owner = res.User
100
		deckResponse.OwnerId = res.UserID
101
	}
102
103
	rating := new(models.Rating)
104
105
	if res := db.Joins("User").Joins("Deck").Where("ratings.deck_id = ? AND ratings.user_id = ?", access.DeckID, access.UserID).First(&rating); res.Error != nil {
106
		deckResponse.PersonnalRating = 0
107
	} else {
108
		deckResponse.PersonnalRating = rating.Value
109
	}
110
111
	var averageValue float32
112
113
	if err := db.Table("ratings").Select("AVG(value)").Where("ratings.deck_id = ? ", access.DeckID).Find(&averageValue).Error; err != nil {
114
		deckResponse.AverageRating = 0
115
	} else {
116
		deckResponse.AverageRating = averageValue
117
	}
118
119
	var count int64
120
	if err := db.Table("cards").Where("cards.deck_id = ?", access.DeckID).Count(&count).Error; err != nil {
121
		deckResponse.CardCount = 0
122
	} else {
123
		deckResponse.CardCount = count
124
	}
125
126
	return *deckResponse
127
}
128
129
func GetDeckOwner(_ *fiber.Ctx, deck models.Deck) *models.Access {
130
	db := database.DBConn
131
132
	access := new(models.Access)
133
134
	if err := db.Joins("User").Joins("Deck").Where("accesses.deck_id =? AND accesses.permission >= ?", deck.ID, models.AccessOwner).Find(&access).Error; err != nil {
135
		return access
136
	}
137
138
	return access
139
}
140
141
// GenerateCreatorAccess function
142
func GenerateCreatorAccess(_ *fiber.Ctx, user *models.User, deck *models.Deck) models.ResponseHTTP {
143
	db := database.DBConn
144
145
	access := new(models.Access)
146
147
	if err := db.Joins("User").Joins("Deck").Where("accesses.user_id = ? AND accesses.deck_id =?", user.ID, deck.ID).Find(&access).Error; err != nil {
148
		if errors.Is(err, gorm.ErrRecordNotFound) {
149
			access.DeckID = deck.ID
150
			access.UserID = user.ID
151
			access.Permission = models.AccessOwner
152
			db.Create(access)
153
		}
154
155
	} else {
156
		if access.Permission >= models.AccessStudent {
157
			return models.ResponseHTTP{
158
				Success: false,
159
				Message: "You are already subscribed to this deck. You can't become an owner...",
160
				Data:    nil,
161
				Count:   0,
162
			}
163
		} else {
164
			access.DeckID = deck.ID
165
			access.UserID = user.ID
166
			access.Permission = models.AccessOwner
167
			db.Preload("User").Preload("Deck").Save(access)
168
		}
169
	}
170
171
	log := CreateLog(models.LogSubscribe, user.Username+" subscribed to "+deck.DeckName)
172
	_ = CreateUserLog(user.ID, *log)
173
	_ = CreateDeckLog(deck.ID, *log)
174
175
	return models.ResponseHTTP{
176
		Success: true,
177
		Message: "Success register a creator access !",
178
		Data:    *access,
179
		Count:   1,
180
	}
181
}
182
183
// GenerateAccess function
184
func GenerateAccess(_ *fiber.Ctx, user *models.User, deck *models.Deck) models.ResponseHTTP {
185
	db := database.DBConn
186
187
	if deck.Status != models.DeckPublic && user.Permissions != models.PermAdmin {
188
		return models.ResponseHTTP{
189
			Success: false,
190
			Message: "You don't have the permissions to subscribe to this deck!",
191
			Data:    nil,
192
			Count:   0,
193
		}
194
	}
195
196
	access := new(models.Access)
197
198
	if err := db.Joins("User").Joins("Deck").Where("accesses.user_id = ? AND accesses.deck_id =?", user.ID, deck.ID).Find(&access).Error; err != nil {
199
		if errors.Is(err, gorm.ErrRecordNotFound) {
200
			access.DeckID = deck.ID
201
			access.UserID = user.ID
202
			access.Permission = models.AccessStudent
203
			db.Preload("User").Preload("Deck").Create(access)
204
		}
205
206
	} else {
207
		if access.Permission >= models.AccessStudent {
208
			return models.ResponseHTTP{
209
				Success: false,
210
				Message: "You are already subscribed to this deck",
211
				Data:    nil,
212
				Count:   0,
213
			}
214
		} else {
215
			access.DeckID = deck.ID
216
			access.UserID = user.ID
217
			access.Permission = models.AccessStudent
218
			db.Preload("User").Preload("Deck").Save(access)
219
		}
220
	}
221
222
	return models.ResponseHTTP{
223
		Success: true,
224
		Message: "Success register an access",
225
		Data:    *access,
226
		Count:   1,
227
	}
228
}
229
230
func CheckAccess(_ *fiber.Ctx, userID uint, deckID uint, perm models.AccessPermission) models.ResponseHTTP {
231
	db := database.DBConn // DB Conn
232
233
	access := new(models.Access)
234
235
	if err := db.Joins("User").Joins("Deck").Where("accesses.user_id = ? AND accesses.deck_id = ?", userID, deckID).First(&access).Error; err != nil {
236
		access.Permission = models.AccessNone
237
	}
238
239
	if access.Permission < perm {
240
		return models.ResponseHTTP{
241
			Success: false,
242
			Message: "You don't have the permission to access this deck!",
243
			Data:    *access,
244
			Count:   1,
245
		}
246
	}
247
248
	return models.ResponseHTTP{
249
		Success: true,
250
		Message: "Success checking access permissions",
251
		Data:    *access,
252
		Count:   1,
253
	}
254
}
255
256
func PostMem(c *fiber.Ctx, user models.User, card models.Card, validation models.CardResponseValidation) models.ResponseHTTP {
257
	db := database.DBConn // DB Conn
258
259
	memDate := new(models.MemDate)
260
261
	if err := db.Joins("Card").Joins("User").Joins("Deck").Where("mem_dates.user_id = ? AND mem_dates.card_id = ?",
262
		&user.ID, card.ID).First(&memDate).Error; err != nil {
263
		return models.ResponseHTTP{
264
			Success: false,
265
			Message: "MemDate Not Found",
266
			Data:    nil,
267
		}
268
	}
269
270
	exMem := FetchMem(c, memDate, &user)
271
	if exMem.Efactor == 0 {
272
		exMem = models.Mem{
273
			UserID:     user.ID,
274
			CardID:     card.ID,
275
			Quality:    0,
276
			Repetition: 0,
277
			Efactor:    2.5,
278
			Interval:   0,
279
		}
280
	}
281
282
	core.UpdateMem(c, &exMem, validation)
283
284
	return models.ResponseHTTP{
285
		Success: true,
286
		Message: "Success Post Mem",
287
		Data:    nil,
288
	}
289
}
290
291
func PopulateMemDate(c *fiber.Ctx, user *models.User, deck *models.Deck) models.ResponseHTTP {
292
	db := database.DBConn // DB Conn
293
	var cards []models.Card
294
295
	if err := db.Joins("Deck").Where("cards.deck_id = ?", deck.ID).Find(&cards).Error; err != nil {
296
		return models.ResponseHTTP{
297
			Success: false,
298
			Message: err.Error(),
299
			Data:    nil,
300
			Count:   0,
301
		}
302
	}
303
304
	for _, s := range cards {
305
306
		_ = GenerateMemDate(c, user, &s)
307
308
	}
309
310
	return models.ResponseHTTP{
311
		Success: true,
312
		Message: "Success generated mem_date",
313
		Data:    nil,
314
		Count:   0,
315
	}
316
}
317
318
func GetSubUsers(_ *fiber.Ctx, deckID uint) []models.User {
319
	db := database.DBConn // DB Conn
320
321
	var users []models.User
322
323
	if err := db.Joins("left join accesses ON users.id = accesses.user_id AND accesses.deck_id = ?", deckID).Where("accesses.permission > ?", models.AccessNone).Find(&users).Error; err != nil {
324
		return nil
325
	}
326
327
	return users
328
329
}
330
331
func GenerateMemDate(_ *fiber.Ctx, user *models.User, card *models.Card) models.ResponseHTTP {
332
	db := database.DBConn // DB Conn
333
334
	memDate := new(models.MemDate)
335
336
	if err := db.Joins("User").Joins("Card").Where("mem_dates.user_id = ? AND mem_dates.card_id = ?", user.ID, card.ID).First(&memDate).Error; err != nil {
337
		if errors.Is(err, gorm.ErrRecordNotFound) {
338
339
			memDate = &models.MemDate{
340
				UserID:   user.ID,
341
				CardID:   card.ID,
342
				DeckID:   card.DeckID,
343
				NextDate: time.Now(),
344
			}
345
346
			db.Create(memDate)
347
		} else {
348
			return models.ResponseHTTP{
349
				Success: false,
350
				Message: err.Error(),
351
				Data:    nil,
352
				Count:   0,
353
			}
354
		}
355
	}
356
357
	return models.ResponseHTTP{
358
		Success: true,
359
		Message: "Success generate MemDate",
360
		Data:    *memDate,
361
		Count:   1,
362
	}
363
}
364
365
// FetchAnswers function
366
func FetchAnswers(_ *fiber.Ctx, card *models.Card) []models.Answer {
367
	var answers []models.Answer
368
	db := database.DBConn // DB Conn
369
370
	if err := db.Joins("Card").Where("answers.card_id = ?", card.ID).Limit(3).Order("random()").Find(&answers).Error; err != nil {
371
		return nil
372
	}
373
374
	return answers
375
}
376
377
func FetchMem(_ *fiber.Ctx, memDate *models.MemDate, user *models.User) models.Mem {
378
	db := database.DBConn // DB Conn
379
380
	mem := new(models.Mem)
381
	if err := db.Joins("Card").Where("mems.card_id = ? AND mems.user_id = ?", memDate.CardID, user.ID).Order("id desc").First(&mem).Error; err != nil {
382
		mem.Efactor = 0
383
	}
384
	return *mem
385
}
386
387
func GenerateAnswers(c *fiber.Ctx, memDate *models.MemDate) []string {
388
	var answersList []string
389
390
	res := FetchAnswers(c, &memDate.Card)
391
392
	if len(res) >= 3 {
393
		answersList = append(answersList, res[0].Answer, res[1].Answer, res[2].Answer, memDate.Card.Answer)
394
395
		rand.Seed(time.Now().UnixNano())
396
		rand.Shuffle(len(answersList), func(i, j int) { answersList[i], answersList[j] = answersList[j], answersList[i] })
397
	}
398
399
	return answersList
400
401
}
402
403
func FetchNextCard(c *fiber.Ctx, user *models.User) models.ResponseHTTP {
404
	db := database.DBConn // DB Conn
405
406
	memDate := new(models.MemDate)
407
	var answersList []string
408
409
	// Get next card
410
	if err := db.Joins(
411
		"left join accesses ON mem_dates.deck_id = accesses.deck_id AND accesses.user_id = ?",
412
		user.ID).Joins("Card").Joins("Deck").Where("mem_dates.user_id = ? AND accesses.permission >= ?",
413
		&user.ID, models.AccessStudent).Limit(1).Order("next_date asc").Find(&memDate).Error; err != nil {
414
		return models.ResponseHTTP{
415
			Success: false,
416
			Message: "Next card not found",
417
			Data:    nil,
418
		}
419
	}
420
421
	mem := FetchMem(c, memDate, user)
422
	if mem.Efactor <= 1.4 || mem.Quality <= 1 || mem.Repetition < 2 {
423
		answersList = GenerateAnswers(c, memDate)
424
		if len(answersList) == 4 {
425
			memDate.Card.Type = 2 // MCQ
426
		}
427
	}
428
429
	return models.ResponseHTTP{
430
		Success: true,
431
		Message: "Get Next Card",
432
		Data: models.ResponseCard{
433
			Card:    memDate.Card,
434
			Answers: answersList,
435
		},
436
	}
437
}
438
439
func FetchNextCardByDeck(c *fiber.Ctx, user *models.User, deckID string) models.ResponseHTTP {
440
	db := database.DBConn // DB Conn
441
442
	memDate := new(models.MemDate)
443
	var answersList []string
444
445
	// Get next card
446
	if err := db.Joins("Card").Joins("User").Joins("Deck").Where("mem_dates.user_id = ? AND mem_dates.deck_id = ?",
447
		&user.ID, deckID).Limit(1).Order("next_date asc").Find(&memDate).Error; err != nil {
448
		return models.ResponseHTTP{
449
			Success: false,
450
			Message: "Next card by deck not found",
451
			Data:    nil,
452
		}
453
	}
454
455
	mem := FetchMem(c, memDate, user)
456
	if mem.Efactor <= 1.4 || mem.Quality <= 1 || mem.Repetition < 2 || memDate.Card.Type == 2 {
457
		answersList = GenerateAnswers(c, memDate)
458
		if len(answersList) == 4 {
459
			memDate.Card.Type = 2 // MCQ
460
		}
461
	}
462
463
	return models.ResponseHTTP{
464
		Success: true,
465
		Message: "Get Next Card By Deck",
466
		Data: models.ResponseCard{
467
			Card:    memDate.Card,
468
			Answers: answersList,
469
		},
470
	}
471
}
472
473
// FetchNextTodayCard function
474
func FetchNextTodayCard(c *fiber.Ctx, user *models.User) models.ResponseHTTP {
475
	db := database.DBConn // DB Conn
476
	memDate := new(models.MemDate)
477
478
	var answersList []string
479
480
	// Get next card with date condition
481
	t := time.Now()
482
483
	if err := db.Joins(
484
		"left join accesses ON mem_dates.deck_id = accesses.deck_id AND accesses.user_id = ?",
485
		user.ID).Joins("Card").Joins("Deck").Where("mem_dates.user_id = ? AND mem_dates.next_date < ? AND accesses.permission >= ?",
486
		&user.ID, t.AddDate(0, 0, 1).Add(
487
			time.Duration(-t.Hour())*time.Hour), models.AccessStudent).Limit(1).Order("next_date asc").Find(&memDate).Error; err != nil {
488
		return models.ResponseHTTP{
489
			Success: false,
490
			Message: "Next today card not found",
491
			Data:    nil,
492
		}
493
	}
494
	mem := FetchMem(c, memDate, user)
495
496
	if mem.Efactor <= 2 || mem.Repetition < 2 || (mem.Efactor <= 2.3 && mem.Repetition < 4) || memDate.Card.Type == 2 {
497
		answersList = GenerateAnswers(c, memDate)
498
		if len(answersList) == 4 {
499
			memDate.Card.Type = 2 // MCQ
500
		}
501
	}
502
503
	return models.ResponseHTTP{
504
		Success: true,
505
		Message: "Get Next Today Card",
506
		Data: models.ResponseCard{
507
			Card:    memDate.Card,
508
			Answers: answersList,
509
		},
510
	}
511
}
512