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

pkg/queries/queries.go   B

Size/Duplication

Total Lines 309
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
cc 47
eloc 183
dl 0
loc 309
rs 8.64
c 0
b 0
f 0

13 Methods

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