Add more comments, fix snake case vars

This commit is contained in:
2024-06-09 18:43:31 -05:00
parent a5d0e70080
commit 87e7da60fa
3 changed files with 48 additions and 33 deletions

14
api.go
View File

@@ -126,9 +126,12 @@ func GetLocations() []Location {
return nil return nil
} }
// Prepare an array to store the locations
cachedLocations = make([]Location, 0, 150) cachedLocations = make([]Location, 0, 150)
// Parse the locations from the HTML
doc.Find("input.property").Each(func(i int, s *goquery.Selection) { doc.Find("input.property").Each(func(i int, s *goquery.Selection) {
// Parse the name and address
matches := parsePattern.FindStringSubmatch(s.Parent().Text()) matches := parsePattern.FindStringSubmatch(s.Parent().Text())
key_attr, _ := s.Attr("data-locate-key") key_attr, _ := s.Attr("data-locate-key")
@@ -136,7 +139,9 @@ func GetLocations() []Location {
id, _ := strconv.ParseUint(id_attr, 10, 32) id, _ := strconv.ParseUint(id_attr, 10, 32)
cachedLocations = append(cachedLocations, Location{ cachedLocations = append(cachedLocations, Location{
id: uint(id), // the ID used for the form, actively used in selecting the registration form
id: uint(id),
// key is not used for anything, but we parse it anyway
key: key_attr, key: key_attr,
name: matches[1], name: matches[1],
address: matches[2] + " " + matches[3], address: matches[2] + " " + matches[3],
@@ -186,6 +191,7 @@ func GetForm(id uint) GetFormResult {
} }
// TODO: Validate that vehicleInformationVIP is actually real for non-VIP properties // TODO: Validate that vehicleInformationVIP is actually real for non-VIP properties
// Get the resident profile // Get the resident profile
nextButton := doc.Find("#vehicleInformationVIP").First() nextButton := doc.Find("#vehicleInformationVIP").First()
residentProfileId, _ := nextButton.Attr("data-resident-profile-id") residentProfileId, _ := nextButton.Attr("data-resident-profile-id")
@@ -293,6 +299,7 @@ func RegisterVehicle(formParams map[string]string, propertyId uint, residentProf
} }
htmlString := string(html) htmlString := string(html)
// Success can be measured with the presence of either "Approved" or "Denied" (if neither, it's an error)
result := &RegistrationResult{success: strings.Contains(htmlString, "Approved")} result := &RegistrationResult{success: strings.Contains(htmlString, "Approved")}
// Sanity check that a proper result was returned // Sanity check that a proper result was returned
@@ -306,7 +313,7 @@ func RegisterVehicle(formParams map[string]string, propertyId uint, residentProf
return nil, fmt.Errorf("failed to parse HTML of approved registration result partial: %w", err) return nil, fmt.Errorf("failed to parse HTML of approved registration result partial: %w", err)
} }
// Success can be measured with the presence of either "Approved" or "Denied" (if neither, it's an error) // Search for attributes thar are only present on success
if result.success { if result.success {
// Search for 'data-vehicle-id' with regex // Search for 'data-vehicle-id' with regex
vehicleIdMatches := vehicleIdPattern.FindStringSubmatch(htmlString) vehicleIdMatches := vehicleIdPattern.FindStringSubmatch(htmlString)
@@ -314,8 +321,9 @@ func RegisterVehicle(formParams map[string]string, propertyId uint, residentProf
result.vehicleId = vehicleIdMatches[1] result.vehicleId = vehicleIdMatches[1]
} }
// Look for a 'p' tag that contains the text 'Confirmation Code:'
var sibling *goquery.Selection var sibling *goquery.Selection
// Look for a 'p' tag that contains the text 'Confirmation Code:'
doc.Find("div.circle-inner > p").Each(func(i int, s *goquery.Selection) { doc.Find("div.circle-inner > p").Each(func(i int, s *goquery.Selection) {
// If we've already found the element, stop searching // If we've already found the element, stop searching
if sibling != nil { if sibling != nil {

View File

@@ -47,19 +47,26 @@ func CodeCommandHandler(session *discordgo.Session, interaction *discordgo.Inter
case discordgo.InteractionApplicationCommand: case discordgo.InteractionApplicationCommand:
data := interaction.ApplicationCommandData() data := interaction.ApplicationCommandData()
location_id, _ := strconv.Atoi(data.Options[0].StringValue()) locationId, _ := strconv.Atoi(data.Options[0].StringValue())
code := data.Options[1].StringValue() code := data.Options[1].StringValue()
user_id, _ := strconv.Atoi(interaction.Member.User.ID) userId, _ := strconv.Atoi(interaction.Member.User.ID)
// TODO: Validate that the location exists // TODO: Validate that the location exists
// TODO: Validate that the code has no invalid characters // TODO: Validate that the code has no invalid characters
already_set := StoreCode(code, int64(location_id), user_id) already_set := StoreCode(code, int64(location_id), user_id)
// Validate that the code has no invalid characters
if !codePattern.MatchString(code) {
HandleError(session, interaction, nil, "The code provided contains invalid characters.")
return
}
alreadySet := StoreCode(code, int64(locationId), userId)
responseText := "Your guest code at \"%s\" has been set." responseText := "Your guest code at \"%s\" has been set."
if already_set { if alreadySet {
responseText = "Your guest code at \"%s\" has been updated." responseText = "Your guest code at \"%s\" has been updated."
} }
location := cachedLocationsMap[uint(location_id)] location := cachedLocationsMap[uint(locationId)]
session.InteractionRespond(interaction.Interaction, &discordgo.InteractionResponse{ session.InteractionRespond(interaction.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource, Type: discordgo.InteractionResponseChannelMessageWithSource,
@@ -86,9 +93,9 @@ func CodeCommandHandler(session *discordgo.Session, interaction *discordgo.Inter
switch { switch {
case LocationOption.Focused: case LocationOption.Focused:
// Seed value is based on the user ID + a 15 minute interval) // Seed value is based on the user ID + a 15 minute interval)
user_id, _ := strconv.Atoi(interaction.Member.User.ID) userId, _ := strconv.Atoi(interaction.Member.User.ID)
seed_value := int64(user_id) + (time.Now().Unix() / 15 * 60) seedValue := int64(userId) + (time.Now().Unix() / 15 * 60)
locations := FilterLocations(GetLocations(), data.Options[0].StringValue(), 25, seed_value) locations := FilterLocations(GetLocations(), data.Options[0].StringValue(), 25, seedValue)
// Convert the locations to choices // Convert the locations to choices
choices = make([]*discordgo.ApplicationCommandOptionChoice, len(locations)) choices = make([]*discordgo.ApplicationCommandOptionChoice, len(locations))
@@ -161,9 +168,9 @@ func RegisterCommandHandler(session *discordgo.Session, interaction *discordgo.I
case discordgo.InteractionApplicationCommand: case discordgo.InteractionApplicationCommand:
data := interaction.ApplicationCommandData() data := interaction.ApplicationCommandData()
location_id, parse_err := strconv.Atoi(data.Options[0].StringValue()) locationId, parseErr := strconv.Atoi(data.Options[0].StringValue())
if parse_err != nil { if parseErr != nil {
HandleError(session, interaction, parse_err, "Error occurred while parsing location id") HandleError(session, interaction, parseErr, "Error occurred while parsing location id")
return return
} }
@@ -183,15 +190,15 @@ func RegisterCommandHandler(session *discordgo.Session, interaction *discordgo.I
} }
// Check if a guest code is required for this location // Check if a guest code is required for this location
guestCodeCondition := GetCodeRequirement(int64(location_id)) guestCodeCondition := GetCodeRequirement(int64(locationId))
// TODO: Add case for when guest code is provided but not required // TODO: Add case for when guest code is provided but not required
// Circumstance under which error is certain // Circumstance under which error is certain
if !guestCodeProvided && guestCodeCondition == GuestCodeNotRequired { if !guestCodeProvided && guestCodeCondition == GuestCodeNotRequired {
// A guest code could be stored, so check for it. // A guest code could be stored, so check for it.
log.WithField("location", location_id).Debug("No guest code provided for location, but one is not required. Checking for stored code.") log.WithField("location", locationId).Debug("No guest code provided for location, but one is not required. Checking for stored code.")
code = GetCode(int64(location_id), int(userId)) code = GetCode(int64(locationId), int(userId))
if code == "" { if code == "" {
// No code was stored, error out. // No code was stored, error out.
@@ -200,8 +207,8 @@ func RegisterCommandHandler(session *discordgo.Session, interaction *discordgo.I
} else { } else {
// Code available, use it. // Code available, use it.
log.WithFields(logrus.Fields{ log.WithFields(logrus.Fields{
"location_id": location_id, "locationId": locationId,
"code": code, "code": code,
}).Debug("Using stored code for location") }).Debug("Using stored code for location")
guestCodeProvided = true guestCodeProvided = true
useStoredCode = true useStoredCode = true
@@ -211,29 +218,29 @@ func RegisterCommandHandler(session *discordgo.Session, interaction *discordgo.I
// Get the form for the location // Get the form for the location
var form GetFormResult var form GetFormResult
if guestCodeProvided { if guestCodeProvided {
form = GetVipForm(uint(location_id), code) form = GetVipForm(uint(locationId), code)
// requireGuestCode being returned for a VIP form indicates an invalid code. // requireGuestCode being returned for a VIP form indicates an invalid code.
if form.requireGuestCode { if form.requireGuestCode {
// Handling is the same for both cases, but the message differs & the code is removed if it was stored. // Handling is the same for both cases, but the message differs & the code is removed if it was stored.
if useStoredCode { if useStoredCode {
HandleError(session, interaction, nil, ":x: This location requires a guest code and the one stored was not valid (and subsequently deleted).") HandleError(session, interaction, nil, ":x: This location requires a guest code and the one stored was not valid (and subsequently deleted).")
RemoveCode(int64(location_id), int(userId)) RemoveCode(int64(locationId), int(userId))
} else { } else {
HandleError(session, interaction, nil, ":x: This location requires a guest code and the one provided was not valid.") HandleError(session, interaction, nil, ":x: This location requires a guest code and the one provided was not valid.")
} }
return return
} }
} else { } else {
form = GetForm(uint(location_id)) form = GetForm(uint(locationId))
if form.requireGuestCode { if form.requireGuestCode {
// The code ended up being required, so we mark it as such. // The code ended up being required, so we mark it as such.
if guestCodeCondition == Unknown { if guestCodeCondition == Unknown {
log.WithFields(logrus.Fields{ log.WithFields(logrus.Fields{
"location_id": location_id, "locationId": locationId,
}).Debug("Marking location as requiring a guest code") }).Debug("Marking location as requiring a guest code")
SetCodeRequirement(int64(location_id), true) SetCodeRequirement(int64(locationId), true)
} }
HandleError(session, interaction, nil, ":x: This location requires a guest code.") HandleError(session, interaction, nil, ":x: This location requires a guest code.")
return return
@@ -258,14 +265,14 @@ func RegisterCommandHandler(session *discordgo.Session, interaction *discordgo.I
// Log the registration context at debug // Log the registration context at debug
log.WithFields(logrus.Fields{ log.WithFields(logrus.Fields{
"registerIdentifier": registerIdentifier, "registerIdentifier": registerIdentifier,
"propertyId": location_id, "propertyId": locationId,
"residentId": form.residentProfileId, "residentId": form.residentProfileId,
}) })
// Store the registration context for later use // Store the registration context for later use
SubmissionContexts.Set(registerIdentifier, &RegisterContext{ SubmissionContexts.Set(registerIdentifier, &RegisterContext{
hiddenKeys: form.hiddenInputs, hiddenKeys: form.hiddenInputs,
propertyId: uint(location_id), propertyId: uint(locationId),
requiredFormKeys: lo.Map(form.fields, func(field Field, _ int) string { requiredFormKeys: lo.Map(form.fields, func(field Field, _ int) string {
return field.id return field.id
}), }),
@@ -281,7 +288,8 @@ func RegisterCommandHandler(session *discordgo.Session, interaction *discordgo.I
Required: false, Required: false,
MinLength: 1, MinLength: 1,
}, },
}}) },
})
response := discordgo.InteractionResponse{ response := discordgo.InteractionResponse{
Type: discordgo.InteractionResponseModal, Type: discordgo.InteractionResponseModal,
@@ -310,9 +318,9 @@ func RegisterCommandHandler(session *discordgo.Session, interaction *discordgo.I
switch focusedOption.Name { switch focusedOption.Name {
case LocationOption.Name: case LocationOption.Name:
// Seed value is based on the user ID + a 15 minute interval) // Seed value is based on the user ID + a 15 minute interval)
user_id, _ := strconv.Atoi(interaction.Member.User.ID) userId, _ := strconv.Atoi(interaction.Member.User.ID)
seed_value := int64(user_id) + (time.Now().Unix() / 15 * 60) seedValue := int64(userId) + (time.Now().Unix() / 15 * 60)
locations := FilterLocations(GetLocations(), data.Options[0].StringValue(), 25, seed_value) locations := FilterLocations(GetLocations(), data.Options[0].StringValue(), 25, seedValue)
// Convert the locations to choices // Convert the locations to choices
choices = make([]*discordgo.ApplicationCommandOptionChoice, len(locations)) choices = make([]*discordgo.ApplicationCommandOptionChoice, len(locations))
@@ -334,7 +342,6 @@ func RegisterCommandHandler(session *discordgo.Session, interaction *discordgo.I
Choices: choices, // This is basically the whole purpose of autocomplete interaction - return custom options to the user. Choices: choices, // This is basically the whole purpose of autocomplete interaction - return custom options to the user.
}, },
}) })
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@@ -90,10 +90,10 @@ func doRequest(request *http.Request) (*http.Response, error) {
} }
// GetRandomItems returns N random items from the given array. // GetRandomItems returns N random items from the given array.
// The seed_value is used to control the output. // The seedValue is used to control the output.
// If the array is not a slice, an error is returned. // If the array is not a slice, an error is returned.
func GetRandomItems[T any](arr []T, N int, seed_value int64) ([]T, error) { func GetRandomItems[T any](arr []T, N int, seedValue int64) ([]T, error) {
randgen := rand.New(rand.NewSource(seed_value)) randgen := rand.New(rand.NewSource(seedValue))
arrValue := reflect.ValueOf(arr) arrValue := reflect.ValueOf(arr)
if arrValue.Kind() != reflect.Slice { if arrValue.Kind() != reflect.Slice {