Passed
Pull Request — main (#71)
by Yume
01:16
created

queries.PopulateMemDate   A

Complexity

Conditions 3

Size

Total Lines 15
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 11
nop 2
dl 0
loc 15
rs 9.85
c 0
b 0
f 0
1
package queries
2
3
import (
4
	"errors"
5
	"fmt"
6
	"github.com/memnix/memnixrest/pkg/database"
7
	"github.com/memnix/memnixrest/pkg/logger"
8
	"github.com/memnix/memnixrest/pkg/models"
9
	"github.com/memnix/memnixrest/pkg/utils"
10
	"gorm.io/gorm"
11
	"math/rand"
12
	"sort"
13
)
14
15
// UpdateSubUsers generates MemDate for sub users
16
func UpdateSubUsers(card *models.Card, user *models.User) error {
17
	var users []models.User
18
	var result *models.ResponseHTTP
19
20
	if result = GetSubUsers(card.DeckID); !result.Success {
21
		log := logger.CreateLog(fmt.Sprintf("Error from %s on deck %d - CreateNewCard: %s", user.Email, card.DeckID, result.Message),
22
			logger.LogQueryGetError).SetType(logger.LogTypeError).AttachIDs(user.ID, card.DeckID, card.ID)
23
		_ = log.SendLog()
24
		return errors.New("couldn't get sub users")
25
	}
26
27
	switch result.Data.(type) {
28
	default:
29
		return errors.New("couldn't get sub users")
30
	case []models.User:
31
		users = result.Data.([]models.User)
32
	}
33
34
	for i := range users {
35
		_ = GenerateMemDate(users[i].ID, card.ID, card.DeckID)
36
	}
37
38
	return nil
39
}
40
41
// FillResponseDeck returns a filled models.ResponseDeck
42
// This function might become a method of models.ResponseDeck
43
func FillResponseDeck(deck *models.Deck, permission models.AccessPermission, toggleToday bool) models.ResponseDeck {
44
	db := database.DBConn
45
46
	deckResponse := models.ResponseDeck{
47
		Deck:        *deck,
48
		DeckID:      deck.ID,
49
		Permission:  permission,
50
		ToggleToday: toggleToday,
51
		OwnerID:     0,
52
		Owner:       models.PublicUser{},
53
	}
54
55
	if owner := deck.GetOwner(); owner.ID != 0 {
56
		publicUser := new(models.PublicUser)
57
58
		publicUser.Set(&owner)
59
60
		deckResponse.Owner = *publicUser
61
		deckResponse.OwnerID = owner.ID
62
	}
63
64
	var count int64
65
	if err := db.Table("cards").Where("cards.deck_id = ?", deck.ID).Count(&count).Error; err != nil {
66
		deckResponse.CardCount = 0
67
	} else {
68
		deckResponse.CardCount = uint16(count)
69
	}
70
	return deckResponse
71
}
72
73
// GenerateCreatorAccess sets an user as a deck creator
74
func GenerateCreatorAccess(user *models.User, deck *models.Deck) *models.ResponseHTTP {
75
	db := database.DBConn
76
	// TODO: Change models.User & models.Deck to uint
77
	access := new(models.Access)
78
	res := new(models.ResponseHTTP)
79
80
	access.Set(user.ID, deck.ID, models.AccessOwner)
81
	db.Create(access)
82
83
	res.GenerateSuccess("Success register a creator access !", *access, 1)
84
	return res
85
}
86
87
// GenerateAccess sets a default student access to a deck for a given user
88
func GenerateAccess(user *models.User, deck *models.Deck) *models.ResponseHTTP {
89
	db := database.DBConn
90
	res := new(models.ResponseHTTP)
91
92
	if deck.Status != models.DeckPublic && user.Permissions != models.PermAdmin {
93
		res.GenerateError(utils.ErrorForbidden)
94
		return res
95
	}
96
97
	access := new(models.Access)
98
99
	if err := db.Joins("User").Joins("Deck").Where("accesses.user_id = ? AND accesses.deck_id =?", user.ID, deck.ID).Find(&access).Error; err != nil {
100
		if errors.Is(err, gorm.ErrRecordNotFound) {
101
			access.Set(user.ID, deck.ID, models.AccessStudent)
102
			db.Preload("User").Preload("Deck").Create(access)
103
		}
104
	} else {
105
		if access.Permission >= models.AccessStudent {
106
			res.GenerateError(utils.ErrorAlreadySub)
107
			return res
108
		}
109
		access.Set(user.ID, deck.ID, models.AccessStudent)
110
		db.Preload("User").Preload("Deck").Save(access)
111
	}
112
113
	res.GenerateSuccess("Success register an access", *access, 1)
114
	return res
115
}
116
117
// CheckAccess verifies if a given user as the right models.Permission to perform an action on a deck
118
func CheckAccess(userID, deckID uint, perm models.AccessPermission) *models.ResponseHTTP {
119
	db := database.DBConn // DB Conn
120
121
	access := new(models.Access)
122
	res := new(models.ResponseHTTP)
123
124
	if err := db.Joins("User").Joins("Deck").Where("accesses.user_id = ? AND accesses.deck_id = ?", userID, deckID).First(&access).Error; err != nil {
125
		access.Permission = models.AccessNone
126
	}
127
128
	if access.Permission < perm {
129
		res.GenerateError(utils.ErrorForbidden)
130
		return res
131
	}
132
133
	res.GenerateSuccess("Success checking access permissions", *access, 1)
134
	return res
135
}
136
137
// CheckCardLimit verifies that a deck can handle more cards
138
func CheckCardLimit(permission models.Permission, deckID uint) bool {
139
	db := database.DBConn // DB Conn
140
	var count int64
141
142
	if err := db.Table("cards").Where("cards.deck_id = ? AND cards.deleted_at IS NULL", deckID).Count(&count).Error; err != nil {
143
		//TODO: Handle error
144
		return true
145
	}
146
147
	if permission < models.PermMod && count >= utils.MaxCardDeck {
148
		return false
149
	}
150
151
	return true
152
}
153
154
// CheckCode prevents deck code from being duplicated
155
func CheckCode(key, code string) bool {
156
	db := database.DBConn // DB Conn
157
	var count int64
158
159
	if err := db.Table("decks").Where("decks.key = ? AND decks.code = ? AND decks.deleted_at IS NULL", key, code).Count(&count).Error; err != nil {
160
		// TODO: Handle error
161
		return true
162
	}
163
164
	if count != 0 {
165
		return false
166
	}
167
168
	return true
169
}
170
171
// CheckDeckLimit verifies that the user hasn't reached the limit
172
func CheckDeckLimit(user *models.User) bool {
173
	db := database.DBConn // DB Conn
174
	var count int64
175
176
	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 {
177
		//TODO: Handle error
178
		return true
179
	}
180
181
	if user.Permissions < models.PermMod && count >= utils.MaxDeckNormalUser {
182
		return false
183
	}
184
185
	return true
186
}
187
188
// PopulateMemDate with default value for a given user & deck
189
// This is used on deck sub
190
func PopulateMemDate(user *models.User, deck *models.Deck) *models.ResponseHTTP {
191
	db := database.DBConn // DB Conn
192
	var cards []models.Card
193
	res := new(models.ResponseHTTP)
194
195
	if err := db.Joins("Deck").Where("cards.deck_id = ?", deck.ID).Find(&cards).Error; err != nil {
196
		res.GenerateError(err.Error()) // MemDate not found
197
		return res
198
	}
199
200
	for i := range cards {
201
		_ = GenerateMemDate(user.ID, cards[i].ID, cards[i].DeckID)
202
	}
203
	res.GenerateSuccess("Success generated mem_date", nil, 0)
204
	return res
205
}
206
207
// GetSubUsers returns a list of users sub to a deck
208
func GetSubUsers(deckID uint) *models.ResponseHTTP {
209
	res := new(models.ResponseHTTP)
210
211
	db := database.DBConn // DB Conn
212
	var users []models.User
213
214
	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 {
215
		res.GenerateError(err.Error())
216
		return res
217
	}
218
	res.GenerateSuccess("Success getting sub users", users, len(users))
219
	return res
220
}
221
222
// GenerateMCQ returns a list of answer
223
func GenerateMCQ(memDate *models.MemDate, userID uint) []string {
224
	mem := FetchMem(memDate.CardID, userID)
225
226
	answersList := make([]string, 4)
227
	if mem.IsMCQ() || memDate.Card.Type == models.CardMCQ {
228
		answersList = memDate.Card.GetMCQAnswers()
229
		if len(answersList) == 4 {
230
			memDate.Card.Type = models.CardMCQ // MCQ
231
		}
232
233
		return answersList
234
	}
235
236
	return answersList
237
}
238
239
// FetchTrainingCards returns training cards
240
func FetchTrainingCards(userID, deckID uint) *models.ResponseHTTP {
241
	res := new(models.ResponseHTTP)
242
	db := database.DBConn // DB Conn
243
244
	var memDates []models.MemDate
245
246
	if err := db.Joins("Deck").Joins("Card").Where("mem_dates.deck_id = ? AND mem_dates.user_id = ?", deckID, userID).Find(&memDates).Error; err != nil {
247
		res.GenerateError(err.Error())
248
		return res
249
	}
250
	responseCard := new(models.ResponseCard)
251
	var answersList []string
252
253
	result := make([]models.ResponseCard, len(memDates))
254
255
	for i := range memDates {
256
		answersList = GenerateMCQ(&memDates[i], userID)
257
		responseCard.Set(&memDates[i], answersList)
258
		result[i] = *responseCard
259
	}
260
261
	rand.Shuffle(len(result), func(i, j int) { result[i], result[j] = result[j], result[i] })
262
263
	res.GenerateSuccess("Success getting next card", result, len(result))
264
	return res
265
}
266
267
// FetchTodayCard return today cards
268
func FetchTodayCard(userID uint) *models.ResponseHTTP {
269
	db := database.DBConn // DB Conn
270
271
	res := new(models.ResponseHTTP)
272
273
	memDates, err := FetchTodayMemDate(userID)
274
	if err != nil {
275
		res.GenerateError(err.Error())
276
		return res
277
	}
278
279
	m, err := GenerateResponseCardMap(memDates, userID)
280
	if err != nil {
281
		res.GenerateError(err.Error())
282
		return res
283
	}
284
285
	todayResponse := new(models.TodayResponse)
286
287
	for key := range m {
288
		deck := new(models.Deck)
289
		_ = db.First(&deck, key).Error
290
		deckResponse := models.DeckResponse{
291
			DeckID: key,
292
			Cards:  m[key],
293
			Count:  len(m[key]),
294
			Deck:   *deck,
295
		}
296
		todayResponse.AppendDeckResponse(deckResponse)
297
	}
298
299
	sort.Slice(todayResponse.DecksReponses, func(i, j int) bool {
300
		return todayResponse.DecksReponses[i].Count < todayResponse.DecksReponses[j].Count
301
	})
302
303
	todayResponse.Count = len(todayResponse.DecksReponses)
304
305
	res.GenerateSuccess("Success getting next today's cards", todayResponse, len(memDates))
306
	return res
307
}
308