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

queries.PostSelfEvaluatedMem   A

Complexity

Conditions 3

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 14
nop 4
dl 0
loc 22
rs 9.7
c 0
b 0
f 0
1
package queries
2
3
import (
4
	"errors"
5
	"fmt"
6
	"math/rand"
7
	"time"
8
9
	"github.com/memnix/memnixrest/app/models"
10
	"github.com/memnix/memnixrest/pkg/core"
11
	"github.com/memnix/memnixrest/pkg/database"
12
	"github.com/memnix/memnixrest/pkg/utils"
13
	"gorm.io/gorm"
14
)
15
16
// UpdateSubUsers generates MemDate for sub users
17
func UpdateSubUsers(card *models.Card, user *models.User) error {
18
	var users []models.User
19
	var result *models.ResponseHTTP
20
21
	if result = GetSubUsers(card.DeckID); !result.Success {
22
		log := models.CreateLog(fmt.Sprintf("Error from %s on deck %d - CreateNewCard: %s", user.Email, card.DeckID, result.Message),
23
			models.LogQueryGetError).SetType(models.LogTypeError).AttachIDs(user.ID, card.DeckID, card.ID)
24
		_ = log.SendLog()
25
		return errors.New("couldn't get sub users")
26
	}
27
28
	switch result.Data.(type) {
29
	default:
30
		return errors.New("couldn't get sub users")
31
	case []models.User:
32
		users = result.Data.([]models.User)
33
	}
34
35
	for i := range users {
36
		_ = GenerateMemDate(users[i].ID, card.ID, card.DeckID)
37
	}
38
39
	return nil
40
}
41
42
// FillResponseDeck returns a filled models.ResponseDeck
43
// This function might become a method of models.ResponseDeck
44
func FillResponseDeck(deck *models.Deck, permission models.AccessPermission, toggleToday bool) models.ResponseDeck {
45
	db := database.DBConn
46
47
	deckResponse := new(models.ResponseDeck)
48
49
	deckResponse.Deck = *deck
50
	deckResponse.DeckID = deck.ID
51
	deckResponse.Permission = permission
52
	deckResponse.ToggleToday = toggleToday
53
54
	if owner := deck.GetOwner(); owner.ID != 0 {
55
		publicUser := new(models.PublicUser)
56
57
		publicUser.Set(&owner)
58
59
		deckResponse.Owner = *publicUser
60
		deckResponse.OwnerID = owner.ID
61
	}
62
63
	var count int64
64
	if err := db.Table("cards").Where("cards.deck_id = ?", deck.ID).Count(&count).Error; err != nil {
65
		deckResponse.CardCount = 0
66
	} else {
67
		deckResponse.CardCount = uint16(count)
68
	}
69
	return *deckResponse
70
}
71
72
// GenerateCreatorAccess sets an user as a deck creator
73
func GenerateCreatorAccess(user *models.User, deck *models.Deck) *models.ResponseHTTP {
74
	db := database.DBConn
75
	// TODO: Change models.User & models.Deck to uint
76
	access := new(models.Access)
77
	res := new(models.ResponseHTTP)
78
79
	access.Set(user.ID, deck.ID, models.AccessOwner)
80
	db.Create(access)
81
82
	res.GenerateSuccess("Success register a creator access !", *access, 1)
83
	return res
84
}
85
86
// GenerateAccess sets a default student access to a deck for a given user
87
func GenerateAccess(user *models.User, deck *models.Deck) *models.ResponseHTTP {
88
	db := database.DBConn
89
	res := new(models.ResponseHTTP)
90
91
	if deck.Status != models.DeckPublic && user.Permissions != models.PermAdmin {
92
		res.GenerateError(utils.ErrorForbidden)
93
		return res
94
	}
95
96
	access := new(models.Access)
97
98
	if err := db.Joins("User").Joins("Deck").Where("accesses.user_id = ? AND accesses.deck_id =?", user.ID, deck.ID).Find(&access).Error; err != nil {
99
		if errors.Is(err, gorm.ErrRecordNotFound) {
100
			access.Set(user.ID, deck.ID, models.AccessStudent)
101
			db.Preload("User").Preload("Deck").Create(access)
102
		}
103
	} else {
104
		if access.Permission >= models.AccessStudent {
105
			res.GenerateError(utils.ErrorAlreadySub)
106
			return res
107
		}
108
		access.Set(user.ID, deck.ID, models.AccessStudent)
109
		db.Preload("User").Preload("Deck").Save(access)
110
	}
111
112
	res.GenerateSuccess("Success register an access", *access, 1)
113
	return res
114
}
115
116
// CheckAccess verifies if a given user as the right models.Permission to perform an action on a deck
117
func CheckAccess(userID, deckID uint, perm models.AccessPermission) *models.ResponseHTTP {
118
	db := database.DBConn // DB Conn
119
120
	access := new(models.Access)
121
	res := new(models.ResponseHTTP)
122
123
	if err := db.Joins("User").Joins("Deck").Where("accesses.user_id = ? AND accesses.deck_id = ?", userID, deckID).First(&access).Error; err != nil {
124
		access.Permission = models.AccessNone
125
	}
126
127
	if access.Permission < perm {
128
		res.GenerateError(utils.ErrorForbidden)
129
		return res
130
	}
131
132
	res.GenerateSuccess("Success checking access permissions", *access, 1)
133
	return res
134
}
135
136
// CheckCardLimit verifies that a deck can handle more cards
137
func CheckCardLimit(permission models.Permission, deckID uint) bool {
138
	db := database.DBConn // DB Conn
139
	var count int64
140
141
	if err := db.Table("cards").Where("cards.deck_id = ? AND cards.deleted_at IS NULL", deckID).Count(&count).Error; err != nil {
142
		//TODO: Handle error
143
		return true
144
	}
145
146
	if permission < models.PermMod && count >= utils.MaxCardDeck {
147
		return false
148
	}
149
150
	return true
151
}
152
153
// CheckCode prevents deck code from being duplicated
154
func CheckCode(key, code string) bool {
155
	db := database.DBConn // DB Conn
156
	var count int64
157
158
	if err := db.Table("decks").Where("decks.key = ? AND decks.code = ? AND decks.deleted_at IS NULL", key, code).Count(&count).Error; err != nil {
159
		// TODO: Handle error
160
		return true
161
	}
162
163
	if count != 0 {
164
		return false
165
	}
166
167
	return true
168
}
169
170
// CheckDeckLimit verifies that the user hasn't reached the limit
171
func CheckDeckLimit(user *models.User) bool {
172
	db := database.DBConn // DB Conn
173
	var count int64
174
175
	if err := db.Table("accesses").Where("accesses.user_id = ? AND accesses.permission = ? AND accesses.deleted_at IS NULL", user.ID, models.AccessOwner).Count(&count).Error; err != nil {
176
		//TODO: Handle error
177
		return true
178
	}
179
180
	if user.Permissions < models.PermMod && count >= utils.MaxDeckNormalUser {
181
		return false
182
	}
183
184
	return true
185
}
186
187
// PostSelfEvaluatedMem updates Mem & MemDate
188
func PostSelfEvaluatedMem(user *models.User, card *models.Card, quality uint, training bool) *models.ResponseHTTP {
189
	db := database.DBConn // DB Conn
190
	res := new(models.ResponseHTTP)
191
192
	memDate := new(models.MemDate)
193
194
	if err := db.Joins("Card").Joins("User").Joins("Deck").Where("mem_dates.user_id = ? AND mem_dates.card_id = ?",
195
		user.ID, card.ID).First(&memDate).Error; err != nil {
196
		res.GenerateError(utils.ErrorRequestFailed) // MemDate not found
197
		// TODO: Create a default MemDate
198
		return res
199
	}
200
201
	exMem := FetchMem(memDate.CardID, user.ID)
202
	if exMem.Efactor == 0 {
203
		exMem.FillDefaultValues(user.ID, card.ID)
204
	}
205
206
	core.UpdateMemSelfEvaluated(&exMem, training, quality)
207
208
	res.GenerateSuccess("Success Post Mem", nil, 0)
209
	return res
210
}
211
212
// PostMem updates MemDate & Mem
213
func PostMem(user *models.User, card *models.Card, validation *models.CardResponseValidation, training bool) *models.ResponseHTTP {
214
	db := database.DBConn // DB Conn
215
	res := new(models.ResponseHTTP)
216
217
	memDate := new(models.MemDate)
218
219
	if err := db.Joins("Card").Joins("User").Joins("Deck").Where("mem_dates.user_id = ? AND mem_dates.card_id = ?",
220
		user.ID, card.ID).First(&memDate).Error; err != nil {
221
		res.GenerateError(utils.ErrorRequestFailed) // MemDate not found
222
		// TODO: Create a default MemDate
223
		return res
224
	}
225
226
	exMem := FetchMem(memDate.CardID, user.ID)
227
	if exMem.Efactor == 0 {
228
		exMem.FillDefaultValues(user.ID, card.ID)
229
	}
230
231
	if training {
232
		core.UpdateMemTraining(&exMem, validation.Validate)
233
	} else {
234
		core.UpdateMem(&exMem, validation.Validate)
235
	}
236
	res.GenerateSuccess("Success Post Mem", nil, 0)
237
	return res
238
}
239
240
// PopulateMemDate with default value for a given user & deck
241
// This is used on deck sub
242
func PopulateMemDate(user *models.User, deck *models.Deck) *models.ResponseHTTP {
243
	db := database.DBConn // DB Conn
244
	var cards []models.Card
245
	res := new(models.ResponseHTTP)
246
247
	if err := db.Joins("Deck").Where("cards.deck_id = ?", deck.ID).Find(&cards).Error; err != nil {
248
		res.GenerateError(err.Error()) // MemDate not found
249
		return res
250
	}
251
252
	for i := range cards {
253
		_ = GenerateMemDate(user.ID, cards[i].ID, cards[i].DeckID)
254
	}
255
	res.GenerateSuccess("Success generated mem_date", nil, 0)
256
	return res
257
}
258
259
// GetSubUsers returns a list of users sub to a deck
260
func GetSubUsers(deckID uint) *models.ResponseHTTP {
261
	res := new(models.ResponseHTTP)
262
263
	db := database.DBConn // DB Conn
264
	var users []models.User
265
266
	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 {
267
		res.GenerateError(err.Error())
268
		return res
269
	}
270
	res.GenerateSuccess("Success getting sub users", users, len(users))
271
	return res
272
}
273
274
// GenerateMemDate with default nextDate
275
func GenerateMemDate(userID, cardID, deckID uint) *models.ResponseHTTP {
276
	db := database.DBConn // DB Conn
277
	res := new(models.ResponseHTTP)
278
279
	memDate := new(models.MemDate)
280
281
	if err := db.Joins("User").Joins("Card").Where("mem_dates.user_id = ? AND mem_dates.card_id = ?", userID, cardID).First(&memDate).Error; err != nil {
282
		if errors.Is(err, gorm.ErrRecordNotFound) {
283
			memDate.SetDefaultNextDate(userID, cardID, deckID)
284
			db.Create(memDate)
285
		} else {
286
			res.GenerateError(err.Error())
287
			return res
288
		}
289
	}
290
	res.GenerateSuccess("Success generate MemDate", memDate, 1)
291
	return res
292
}
293
294
// FetchMem returns last mem of an user on a given card
295
func FetchMem(cardID, userID uint) models.Mem {
296
	db := database.DBConn // DB Conn
297
298
	mem := new(models.Mem)
299
	if err := db.Joins("Card").Where("mems.card_id = ? AND mems.user_id = ?", cardID, userID).Order("id desc").First(&mem).Error; err != nil {
300
		if errors.Is(err, gorm.ErrRecordNotFound) {
301
			mem.Efactor = 0
302
		}
303
	}
304
	return *mem
305
}
306
307
// GenerateMCQ returns a list of answer
308
func GenerateMCQ(memDate *models.MemDate, userID uint) []string {
309
	mem := FetchMem(memDate.CardID, userID)
310
311
	var answersList []string
312
	if mem.IsMCQ() || memDate.Card.Type == models.CardMCQ {
313
		answersList = memDate.Card.GetMCQAnswers()
314
		if len(answersList) == 4 {
315
			memDate.Card.Type = models.CardMCQ // MCQ
316
		}
317
		return answersList
318
	}
319
320
	return answersList
321
}
322
323
// FetchTrainingCards returns training cards
324
func FetchTrainingCards(userID, deckID uint) *models.ResponseHTTP {
325
	res := new(models.ResponseHTTP)
326
	db := database.DBConn // DB Conn
327
328
	var memDates []models.MemDate
329
330
	if err := db.Joins("Deck").Joins("Card").Where("mem_dates.deck_id = ? AND mem_dates.user_id = ?", deckID, userID).Find(&memDates).Error; err != nil {
331
		res.GenerateError(err.Error())
332
		return res
333
	}
334
	responseCard := new(models.ResponseCard)
335
	var answersList []string
336
337
	result := make([]models.ResponseCard, len(memDates))
338
339
	for i := range memDates {
340
		answersList = GenerateMCQ(&memDates[i], userID)
341
		responseCard.Set(&memDates[i], answersList)
342
343
		result = append(result, *responseCard)
344
	}
345
346
	rand.Seed(time.Now().UnixNano())
347
	rand.Shuffle(len(result), func(i, j int) { result[i], result[j] = result[j], result[i] })
348
349
	res.GenerateSuccess("Success getting next card", result, len(result))
350
	return res
351
}
352
353
// FetchTodayCard return today cards
354
func FetchTodayCard(userID uint) *models.ResponseHTTP {
355
	db := database.DBConn // DB Conn
356
	t := time.Now()
357
358
	res := new(models.ResponseHTTP)
359
	var memDates []models.MemDate
360
361
	m := make(map[uint][]models.ResponseCard)
362
363
	if err := db.Joins(
364
		"left join accesses ON mem_dates.deck_id = accesses.deck_id AND accesses.user_id = ?",
365
		userID).Joins("Card").Joins("Deck").Where("mem_dates.user_id = ? AND mem_dates.next_date < ? AND accesses.permission >= ? AND accesses.toggle_today IS true",
366
		userID, t.AddDate(0, 0, 1).Add(
367
			time.Duration(-t.Hour())*time.Hour), models.AccessStudent).Order("next_date asc").Find(&memDates).Error; err != nil {
368
		res.GenerateError("Today's memDate not found")
369
		return res
370
	}
371
372
	rand.Seed(time.Now().UnixNano())
373
	rand.Shuffle(len(memDates), func(i, j int) { memDates[i], memDates[j] = memDates[j], memDates[i] })
374
375
	var answersList []string
376
	responseCard := new(models.ResponseCard)
377
378
	for index := range memDates {
379
		answersList = GenerateMCQ(&memDates[index], userID)
380
		responseCard.Set(&memDates[index], answersList)
381
		m[responseCard.Card.DeckID] = append(m[responseCard.Card.DeckID], *responseCard)
382
	}
383
384
	todayResponse := new(models.TodayResponse)
385
386
	for key := range m {
387
		deckResponse := new(models.DeckResponse)
388
		deckResponse.DeckID = key
389
		deckResponse.Cards = m[key]
390
		deckResponse.Count = len(deckResponse.Cards)
391
		todayResponse.DecksReponses = append(todayResponse.DecksReponses, *deckResponse)
392
	}
393
394
	todayResponse.Count = len(todayResponse.DecksReponses)
395
396
	res.GenerateSuccess("Success getting next today's cards", todayResponse, len(memDates))
397
	return res
398
}
399