Passed
Push — main ( ca9167...0507b2 )
by Yume
01:10
created

queries.DeleteRating   A

Complexity

Conditions 2

Size

Total Lines 18
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

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