Passed
Push — main ( 0c4595...320b76 )
by Yume
01:25 queued 12s
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(c *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(c *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
// GenerateAdminAccess
90
func GenerateCreatorAccess(c *fiber.Ctx, user *models.User, deck *models.Deck) models.ResponseHTTP {
91
	db := database.DBConn
92
93
	access := new(models.Access)
94
95
	if err := db.Joins("User").Joins("Deck").Where("accesses.user_id = ? AND accesses.deck_id =?", user.ID, deck.ID).Find(&access).Error; err != nil {
96
		if errors.Is(err, gorm.ErrRecordNotFound) {
97
			access.DeckID = deck.ID
98
			access.UserID = user.ID
99
			access.Permission = models.AccessOwner
100
			db.Create(access)
101
		}
102
103
	} else {
104
		if access.Permission >= models.AccessStudent {
105
			return models.ResponseHTTP{
106
				Success: false,
107
				Message: "You are already subscribed to this deck. You can't become an owner...",
108
				Data:    nil,
109
				Count:   0,
110
			}
111
		} else {
112
			access.DeckID = deck.ID
113
			access.UserID = user.ID
114
			access.Permission = models.AccessOwner
115
			db.Preload("User").Preload("Deck").Save(access)
116
		}
117
	}
118
119
	log := CreateLog(models.LogSubscribe, user.Username+" subscribed to "+deck.DeckName)
120
	_ = CreateUserLog(user.ID, *log)
121
	_ = CreateDeckLog(deck.ID, *log)
122
123
	return models.ResponseHTTP{
124
		Success: true,
125
		Message: "Success register a creator access !",
126
		Data:    *access,
127
		Count:   1,
128
	}
129
}
130
131
// GenerateAccess
132
func GenerateAccess(c *fiber.Ctx, user *models.User, deck *models.Deck) models.ResponseHTTP {
133
	db := database.DBConn
134
135
	if deck.Status != models.DeckPublic && user.Permissions != models.PermAdmin {
136
		return models.ResponseHTTP{
137
			Success: false,
138
			Message: "You don't have the permissions to subscribe to this deck!",
139
			Data:    nil,
140
			Count:   0,
141
		}
142
	}
143
144
	access := new(models.Access)
145
146
	if err := db.Joins("User").Joins("Deck").Where("accesses.user_id = ? AND accesses.deck_id =?", user.ID, deck.ID).Find(&access).Error; err != nil {
147
		if errors.Is(err, gorm.ErrRecordNotFound) {
148
			access.DeckID = deck.ID
149
			access.UserID = user.ID
150
			access.Permission = models.AccessStudent
151
			db.Preload("User").Preload("Deck").Create(access)
152
		}
153
154
	} else {
155
		if access.Permission >= models.AccessStudent {
156
			return models.ResponseHTTP{
157
				Success: false,
158
				Message: "You are already subscribed to this deck",
159
				Data:    nil,
160
				Count:   0,
161
			}
162
		} else {
163
			access.DeckID = deck.ID
164
			access.UserID = user.ID
165
			access.Permission = models.AccessStudent
166
			db.Preload("User").Preload("Deck").Save(access)
167
		}
168
	}
169
170
	return models.ResponseHTTP{
171
		Success: true,
172
		Message: "Success register an access",
173
		Data:    *access,
174
		Count:   1,
175
	}
176
}
177
178
func CheckAccess(c *fiber.Ctx, userID uint, deckID uint, perm models.AccessPermission) models.ResponseHTTP {
179
	db := database.DBConn // DB Conn
180
181
	access := new(models.Access)
182
183
	if err := db.Joins("User").Joins("Deck").Where("accesses.user_id = ? AND accesses.deck_id = ?", userID, deckID).First(&access).Error; err != nil {
184
		access.Permission = models.AccessNone
185
	}
186
187
	if access.Permission < perm {
188
		return models.ResponseHTTP{
189
			Success: false,
190
			Message: "You don't have the permission to access this deck!",
191
			Data:    *access,
192
			Count:   1,
193
		}
194
	}
195
196
	return models.ResponseHTTP{
197
		Success: true,
198
		Message: "Success checking access permissions",
199
		Data:    *access,
200
		Count:   1,
201
	}
202
}
203
204
func MigrateDb(c *fiber.Ctx) {
205
	db := database.DBConn
206
207
	var memDates []models.MemDate
208
	var users []models.User
209
210
	db.Find(&users)
211
212
	ch := make(chan models.Mem)
213
214
	for _, user := range users {
215
		db.Joins("Card").Where("mem_dates.user_id = ?", &user.ID).Find(&memDates)
216
		for _, memDate := range memDates {
217
			go func(c *fiber.Ctx, user *models.User, memDate models.MemDate) {
218
				var mems []models.Mem
219
				db.Joins("Card").Where("mems.card_id = ? AND mems.user_id = ?", memDate.CardID, user.ID).Order("id asc").Find(&mems)
220
				for i, mem := range mems {
221
					if i != len(mems)-1 {
222
						mem.Quality = mems[i+1].Quality
223
						db.Save(&mem)
224
					}
225
					ch <- mem
226
				}
227
			}(c, &user, memDate)
228
		}
229
	}
230
231
}
232
233
func PostMem(c *fiber.Ctx, user models.User, card models.Card, validation models.CardResponseValidation) models.ResponseHTTP {
234
	db := database.DBConn // DB Conn
235
236
	memDate := new(models.MemDate)
237
238
	if err := db.Joins("Card").Joins("User").Joins("Deck").Where("mem_dates.user_id = ? AND mem_dates.card_id = ?",
239
		&user.ID, card.ID).First(&memDate).Error; err != nil {
240
		return models.ResponseHTTP{
241
			Success: false,
242
			Message: "MemDate Not Found",
243
			Data:    nil,
244
		}
245
	}
246
247
	ex_mem := FetchMem(c, memDate, &user)
248
	if ex_mem.Efactor == 0 {
249
		ex_mem = models.Mem{
250
			UserID:     user.ID,
251
			CardID:     card.ID,
252
			Quality:    0,
253
			Repetition: 0,
254
			Efactor:    2.5,
255
			Interval:   0,
256
		}
257
	}
258
259
	core.UpdateMem(c, &ex_mem, validation)
260
261
	return models.ResponseHTTP{
262
		Success: true,
263
		Message: "Success Post Mem",
264
		Data:    nil,
265
	}
266
}
267
268
func PopulateMemDate(c *fiber.Ctx, user *models.User, deck *models.Deck) models.ResponseHTTP {
269
	db := database.DBConn // DB Conn
270
	var cards []models.Card
271
272
	if err := db.Joins("Deck").Where("cards.deck_id = ?", deck.ID).Find(&cards).Error; err != nil {
273
		return models.ResponseHTTP{
274
			Success: false,
275
			Message: err.Error(),
276
			Data:    nil,
277
			Count:   0,
278
		}
279
	}
280
281
	ch := make(chan models.ResponseHTTP)
282
283
	for _, s := range cards {
284
		go func(c *fiber.Ctx, user *models.User, card models.Card) {
285
			res := GenerateMemDate(c, user, &card)
286
			ch <- res
287
		}(c, user, s)
288
	}
289
290
	return models.ResponseHTTP{
291
		Success: true,
292
		Message: "Success generated mem_date",
293
		Data:    nil,
294
		Count:   0,
295
	}
296
}
297
298
func GetSubUsers(c *fiber.Ctx, deckID uint) []models.User {
299
	db := database.DBConn // DB Conn
300
301
	var users []models.User
302
303
	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 {
304
		return nil
305
	}
306
307
	return users
308
309
}
310
311
func GenerateMemDate(c *fiber.Ctx, user *models.User, card *models.Card) models.ResponseHTTP {
312
	db := database.DBConn // DB Conn
313
314
	memDate := new(models.MemDate)
315
316
	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 {
317
		if errors.Is(err, gorm.ErrRecordNotFound) {
318
319
			memDate = &models.MemDate{
320
				UserID:   user.ID,
321
				CardID:   card.ID,
322
				DeckID:   card.DeckID,
323
				NextDate: time.Now(),
324
			}
325
326
			db.Create(memDate)
327
		} else {
328
			return models.ResponseHTTP{
329
				Success: false,
330
				Message: err.Error(),
331
				Data:    nil,
332
				Count:   0,
333
			}
334
		}
335
	}
336
337
	return models.ResponseHTTP{
338
		Success: true,
339
		Message: "Success generate MemDate",
340
		Data:    *memDate,
341
		Count:   1,
342
	}
343
}
344
345
// FetchAnswers
346
func FetchAnswers(c *fiber.Ctx, card *models.Card) []models.Answer {
347
	var answers []models.Answer
348
	db := database.DBConn // DB Conn
349
350
	if err := db.Joins("Card").Where("answers.card_id = ?", card.ID).Limit(3).Order("random()").Find(&answers).Error; err != nil {
351
		return nil
352
	}
353
354
	return answers
355
}
356
357
func FetchMem(c *fiber.Ctx, memDate *models.MemDate, user *models.User) models.Mem {
358
	db := database.DBConn // DB Conn
359
360
	mem := new(models.Mem)
361
	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 {
362
		mem.Efactor = 0
363
	}
364
	return *mem
365
}
366
367
func GenerateAnswers(c *fiber.Ctx, memDate *models.MemDate) []string {
368
	var answersList []string
369
370
	res := FetchAnswers(c, &memDate.Card)
371
372
	if len(res) >= 3 {
373
		answersList = append(answersList, res[0].Answer, res[1].Answer, res[2].Answer, memDate.Card.Answer)
374
375
		rand.Seed(time.Now().UnixNano())
376
		rand.Shuffle(len(answersList), func(i, j int) { answersList[i], answersList[j] = answersList[j], answersList[i] })
377
	}
378
379
	return answersList
380
381
}
382
383
func FetchNextCard(c *fiber.Ctx, user *models.User) models.ResponseHTTP {
384
	db := database.DBConn // DB Conn
385
386
	memDate := new(models.MemDate)
387
	var answersList []string
388
389
	// Get next card
390
	if err := db.Joins(
391
		"left join accesses ON mem_dates.deck_id = accesses.deck_id AND accesses.user_id = ?",
392
		user.ID).Joins("Card").Joins("Deck").Where("mem_dates.user_id = ? AND accesses.permission >= ?",
393
		&user.ID, models.AccessStudent).Limit(1).Order("next_date asc").Find(&memDate).Error; err != nil {
394
		return models.ResponseHTTP{
395
			Success: false,
396
			Message: "Next card not found",
397
			Data:    nil,
398
		}
399
	}
400
401
	mem := FetchMem(c, memDate, user)
402
	if mem.Efactor <= 1.4 || mem.Quality <= 1 || mem.Repetition < 2 {
403
		answersList = GenerateAnswers(c, memDate)
404
		if len(answersList) == 4 {
405
			memDate.Card.Type = 2 // MCQ
406
		}
407
	}
408
409
	return models.ResponseHTTP{
410
		Success: true,
411
		Message: "Get Next Card",
412
		Data: models.ResponseCard{
413
			Card:    memDate.Card,
414
			Answers: answersList,
415
		},
416
	}
417
}
418
419
func FetchNextCardByDeck(c *fiber.Ctx, user *models.User, deckID string) models.ResponseHTTP {
420
	db := database.DBConn // DB Conn
421
422
	memDate := new(models.MemDate)
423
	var answersList []string
424
425
	// Get next card
426
	if err := db.Joins("Card").Joins("User").Joins("Deck").Where("mem_dates.user_id = ? AND mem_dates.deck_id = ?",
427
		&user.ID, deckID).Limit(1).Order("next_date asc").Find(&memDate).Error; err != nil {
428
		return models.ResponseHTTP{
429
			Success: false,
430
			Message: "Next card by deck not found",
431
			Data:    nil,
432
		}
433
	}
434
435
	mem := FetchMem(c, memDate, user)
436
	if mem.Efactor <= 1.4 || mem.Quality <= 1 || mem.Repetition < 2 || memDate.Card.Type == 2 {
437
		answersList = GenerateAnswers(c, memDate)
438
		if len(answersList) == 4 {
439
			memDate.Card.Type = 2 // MCQ
440
		}
441
	}
442
443
	return models.ResponseHTTP{
444
		Success: true,
445
		Message: "Get Next Card By Deck",
446
		Data: models.ResponseCard{
447
			Card:    memDate.Card,
448
			Answers: answersList,
449
		},
450
	}
451
}
452
453
// FetchNextTodayCard
454
func FetchNextTodayCard(c *fiber.Ctx, user *models.User) models.ResponseHTTP {
455
	db := database.DBConn // DB Conn
456
	memDate := new(models.MemDate)
457
458
	var answersList []string
459
460
	// Get next card with date condition
461
	t := time.Now()
462
463
	if err := db.Joins(
464
		"left join accesses ON mem_dates.deck_id = accesses.deck_id AND accesses.user_id = ?",
465
		user.ID).Joins("Card").Joins("Deck").Where("mem_dates.user_id = ? AND mem_dates.next_date < ? AND accesses.permission >= ?",
466
		&user.ID, t.AddDate(0, 0, 1).Add(
467
			time.Duration(-t.Hour())*time.Hour), models.AccessStudent).Limit(1).Order("next_date asc").Find(&memDate).Error; err != nil {
468
		return models.ResponseHTTP{
469
			Success: false,
470
			Message: "Next today card not found",
471
			Data:    nil,
472
		}
473
	}
474
	mem := FetchMem(c, memDate, user)
475
	if mem.Efactor <= 1.4 || mem.Quality <= 1 || mem.Repetition < 2 || memDate.Card.Type == 2 {
476
		answersList = GenerateAnswers(c, memDate)
477
		if len(answersList) == 4 {
478
			memDate.Card.Type = 2 // MCQ
479
		}
480
	}
481
482
	return models.ResponseHTTP{
483
		Success: true,
484
		Message: "Get Next Today Card",
485
		Data: models.ResponseCard{
486
			Card:    memDate.Card,
487
			Answers: answersList,
488
		},
489
	}
490
}
491